Browse Source

Merge branch 'jk/pkt-line-cleanup'

Clean up pkt-line API, implementation and its callers to make them
more robust.

* jk/pkt-line-cleanup:
  do not use GIT_TRACE_PACKET=3 in tests
  remote-curl: always parse incoming refs
  remote-curl: move ref-parsing code up in file
  remote-curl: pass buffer straight to get_remote_heads
  teach get_remote_heads to read from a memory buffer
  pkt-line: share buffer/descriptor reading implementation
  pkt-line: provide a LARGE_PACKET_MAX static buffer
  pkt-line: move LARGE_PACKET_MAX definition from sideband
  pkt-line: teach packet_read_line to chomp newlines
  pkt-line: provide a generic reading function with options
  pkt-line: drop safe_write function
  pkt-line: move a misplaced comment
  write_or_die: raise SIGPIPE when we get EPIPE
  upload-archive: use argv_array to store client arguments
  upload-archive: do not copy repo name
  send-pack: prefer prefixcmp over memcmp in receive_status
  fetch-pack: fix out-of-bounds buffer offset in get_ack
  upload-pack: remove packet debugging harness
  upload-pack: do not add duplicate objects to shallow list
  upload-pack: use get_sha1_hex to parse "shallow" lines
maint
Junio C Hamano 12 years ago
parent
commit
e013bdab0f
  1. 17
      builtin/archive.c
  2. 11
      builtin/fetch-pack.c
  3. 10
      builtin/receive-pack.c
  4. 4
      builtin/send-pack.c
  5. 45
      builtin/upload-archive.c
  6. 4
      cache.h
  7. 13
      connect.c
  8. 4
      daemon.c
  9. 18
      fetch-pack.c
  10. 8
      http-backend.c
  11. 1
      http.c
  12. 125
      pkt-line.c
  13. 72
      pkt-line.h
  14. 188
      remote-curl.c
  15. 22
      send-pack.c
  16. 11
      sideband.c
  17. 3
      sideband.h
  18. 64
      t/t5503-tagfollow.sh
  19. 18
      t/t5700-clone-reference.sh
  20. 6
      transport.c
  21. 40
      upload-pack.c
  22. 19
      write_or_die.c

17
builtin/archive.c

@ -27,8 +27,8 @@ static int run_remote_archiver(int argc, const char **argv, @@ -27,8 +27,8 @@ static int run_remote_archiver(int argc, const char **argv,
const char *remote, const char *exec,
const char *name_hint)
{
char buf[LARGE_PACKET_MAX];
int fd[2], i, len, rv;
char *buf;
int fd[2], i, rv;
struct transport *transport;
struct remote *_remote;

@ -53,21 +53,18 @@ static int run_remote_archiver(int argc, const char **argv, @@ -53,21 +53,18 @@ static int run_remote_archiver(int argc, const char **argv,
packet_write(fd[1], "argument %s\n", argv[i]);
packet_flush(fd[1]);

len = packet_read_line(fd[0], buf, sizeof(buf));
if (!len)
buf = packet_read_line(fd[0], NULL);
if (!buf)
die(_("git archive: expected ACK/NAK, got EOF"));
if (buf[len-1] == '\n')
buf[--len] = 0;
if (strcmp(buf, "ACK")) {
if (len > 5 && !prefixcmp(buf, "NACK "))
if (!prefixcmp(buf, "NACK "))
die(_("git archive: NACK %s"), buf + 5);
if (len > 4 && !prefixcmp(buf, "ERR "))
if (!prefixcmp(buf, "ERR "))
die(_("remote error: %s"), buf + 4);
die(_("git archive: protocol error"));
}

len = packet_read_line(fd[0], buf, sizeof(buf));
if (len)
if (packet_read_line(fd[0], NULL))
die(_("git archive: expected a flush"));

/* Now, start reading from fd[0] and spit it out to stdout */

11
builtin/fetch-pack.c

@ -119,14 +119,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) @@ -119,14 +119,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
/* in stateless RPC mode we use pkt-line to read
* from stdin, until we get a flush packet
*/
static char line[1000];
for (;;) {
int n = packet_read_line(0, line, sizeof(line));
if (!n)
char *line = packet_read_line(0, NULL);
if (!line)
break;
if (line[n-1] == '\n')
n--;
add_sought_entry_mem(&sought, &nr_sought, &alloc_sought, line, n);
add_sought_entry(&sought, &nr_sought, &alloc_sought, line);
}
}
else {
@ -147,7 +144,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) @@ -147,7 +144,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
args.verbose ? CONNECT_VERBOSE : 0);
}

get_remote_heads(fd[0], &ref, 0, NULL);
get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL);

ref = fetch_pack(&args, fd, conn, ref, dest,
sought, nr_sought, pack_lockfile_ptr);

10
builtin/receive-pack.c

@ -754,17 +754,15 @@ static struct command *read_head_info(void) @@ -754,17 +754,15 @@ static struct command *read_head_info(void)
struct command *commands = NULL;
struct command **p = &commands;
for (;;) {
static char line[1000];
char *line;
unsigned char old_sha1[20], new_sha1[20];
struct command *cmd;
char *refname;
int len, reflen;

len = packet_read_line(0, line, sizeof(line));
if (!len)
line = packet_read_line(0, &len);
if (!line)
break;
if (line[len-1] == '\n')
line[--len] = 0;
if (len < 83 ||
line[40] != ' ' ||
line[81] != ' ' ||
@ -932,7 +930,7 @@ static void report(struct command *commands, const char *unpack_status) @@ -932,7 +930,7 @@ static void report(struct command *commands, const char *unpack_status)
if (use_sideband)
send_sideband(1, 1, buf.buf, buf.len, use_sideband);
else
safe_write(1, buf.buf, buf.len);
write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
}


4
builtin/send-pack.c

@ -79,7 +79,7 @@ static void print_helper_status(struct ref *ref) @@ -79,7 +79,7 @@ static void print_helper_status(struct ref *ref)
}
strbuf_addch(&buf, '\n');

safe_write(1, buf.buf, buf.len);
write_or_die(1, buf.buf, buf.len);
}
strbuf_release(&buf);
}
@ -207,7 +207,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) @@ -207,7 +207,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)

memset(&extra_have, 0, sizeof(extra_have));

get_remote_heads(fd[0], &remote_refs, REF_NORMAL, &extra_have);
get_remote_heads(fd[0], NULL, 0, &remote_refs, REF_NORMAL, &extra_have);

transport_verify_remote_names(nr_refspecs, refspecs);


45
builtin/upload-archive.c

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
#include "pkt-line.h"
#include "sideband.h"
#include "run-command.h"
#include "argv-array.h"

static const char upload_archive_usage[] =
"git upload-archive <repo>";
@ -18,51 +19,31 @@ static const char deadchild[] = @@ -18,51 +19,31 @@ static const char deadchild[] =

int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
{
const char *sent_argv[MAX_ARGS];
struct argv_array sent_argv = ARGV_ARRAY_INIT;
const char *arg_cmd = "argument ";
char *p, buf[4096];
int sent_argc;
int len;

if (argc != 2)
usage(upload_archive_usage);

if (strlen(argv[1]) + 1 > sizeof(buf))
die("insanely long repository name");

strcpy(buf, argv[1]); /* enter-repo smudges its argument */

if (!enter_repo(buf, 0))
die("'%s' does not appear to be a git repository", buf);
if (!enter_repo(argv[1], 0))
die("'%s' does not appear to be a git repository", argv[1]);

/* put received options in sent_argv[] */
sent_argc = 1;
sent_argv[0] = "git-upload-archive";
for (p = buf;;) {
/* This will die if not enough free space in buf */
len = packet_read_line(0, p, (buf + sizeof buf) - p);
if (len == 0)
argv_array_push(&sent_argv, "git-upload-archive");
for (;;) {
char *buf = packet_read_line(0, NULL);
if (!buf)
break; /* got a flush */
if (sent_argc > MAX_ARGS - 2)
die("Too many options (>%d)", MAX_ARGS - 2);
if (sent_argv.argc > MAX_ARGS)
die("Too many options (>%d)", MAX_ARGS - 1);

if (p[len-1] == '\n') {
p[--len] = 0;
}
if (len < strlen(arg_cmd) ||
strncmp(arg_cmd, p, strlen(arg_cmd)))
if (prefixcmp(buf, arg_cmd))
die("'argument' token or flush expected");

len -= strlen(arg_cmd);
memmove(p, p + strlen(arg_cmd), len);
sent_argv[sent_argc++] = p;
p += len;
*p++ = 0;
argv_array_push(&sent_argv, buf + strlen(arg_cmd));
}
sent_argv[sent_argc] = NULL;

/* parse all options sent by the client */
return write_archive(sent_argc, sent_argv, prefix, 0, NULL, 1);
return write_archive(sent_argv.argc, sent_argv.argv, prefix, 0, NULL, 1);
}

__attribute__((format (printf, 1, 2)))

4
cache.h

@ -1064,7 +1064,9 @@ struct extra_have_objects { @@ -1064,7 +1064,9 @@ struct extra_have_objects {
int nr, alloc;
unsigned char (*array)[20];
};
extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
extern struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
struct ref **list, unsigned int flags,
struct extra_have_objects *);
extern int server_supports(const char *feature);
extern int parse_feature_request(const char *features, const char *feature);
extern const char *server_feature_value(const char *feature, int *len_ret);

13
connect.c

@ -62,8 +62,8 @@ static void die_initial_contact(int got_at_least_one_head) @@ -62,8 +62,8 @@ static void die_initial_contact(int got_at_least_one_head)
/*
* Read all the refs from the other end
*/
struct ref **get_remote_heads(int in, struct ref **list,
unsigned int flags,
struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
struct ref **list, unsigned int flags,
struct extra_have_objects *extra_have)
{
int got_at_least_one_head = 0;
@ -72,18 +72,19 @@ struct ref **get_remote_heads(int in, struct ref **list, @@ -72,18 +72,19 @@ struct ref **get_remote_heads(int in, struct ref **list,
for (;;) {
struct ref *ref;
unsigned char old_sha1[20];
static char buffer[1000];
char *name;
int len, name_len;
char *buffer = packet_buffer;

len = packet_read(in, buffer, sizeof(buffer));
len = packet_read(in, &src_buf, &src_len,
packet_buffer, sizeof(packet_buffer),
PACKET_READ_GENTLE_ON_EOF |
PACKET_READ_CHOMP_NEWLINE);
if (len < 0)
die_initial_contact(got_at_least_one_head);

if (!len)
break;
if (buffer[len-1] == '\n')
buffer[--len] = 0;

if (len > 4 && !prefixcmp(buffer, "ERR "))
die("remote error: %s", buffer + 4);

4
daemon.c

@ -600,7 +600,7 @@ static void parse_host_arg(char *extra_args, int buflen) @@ -600,7 +600,7 @@ static void parse_host_arg(char *extra_args, int buflen)

static int execute(void)
{
static char line[1000];
char *line = packet_buffer;
int pktlen, len, i;
char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");

@ -608,7 +608,7 @@ static int execute(void) @@ -608,7 +608,7 @@ static int execute(void)
loginfo("Connection from %s:%s", addr, port);

alarm(init_timeout ? init_timeout : timeout);
pktlen = packet_read_line(0, line, sizeof(line));
pktlen = packet_read(0, NULL, NULL, packet_buffer, sizeof(packet_buffer), 0);
alarm(0);

len = strlen(line);

18
fetch-pack.c

@ -172,8 +172,8 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd) @@ -172,8 +172,8 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
* shallow and unshallow commands every time there
* is a block of have lines exchanged.
*/
char line[1000];
while (packet_read_line(fd, line, sizeof(line))) {
char *line;
while ((line = packet_read_line(fd, NULL))) {
if (!prefixcmp(line, "shallow "))
continue;
if (!prefixcmp(line, "unshallow "))
@ -215,17 +215,17 @@ static int write_shallow_commits(struct strbuf *out, int use_pack_protocol) @@ -215,17 +215,17 @@ static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)

static enum ack_type get_ack(int fd, unsigned char *result_sha1)
{
static char line[1000];
int len = packet_read_line(fd, line, sizeof(line));
int len;
char *line = packet_read_line(fd, &len);

if (!len)
die("git fetch-pack: expected ACK/NAK, got EOF");
if (line[len-1] == '\n')
line[--len] = 0;
if (!strcmp(line, "NAK"))
return NAK;
if (!prefixcmp(line, "ACK ")) {
if (!get_sha1_hex(line+4, result_sha1)) {
if (len < 45)
return ACK;
if (strstr(line+45, "continue"))
return ACK_continue;
if (strstr(line+45, "common"))
@ -245,7 +245,7 @@ static void send_request(struct fetch_pack_args *args, @@ -245,7 +245,7 @@ static void send_request(struct fetch_pack_args *args,
send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
packet_flush(fd);
} else
safe_write(fd, buf->buf, buf->len);
write_or_die(fd, buf->buf, buf->len);
}

static void insert_one_alternate_ref(const struct ref *ref, void *unused)
@ -346,11 +346,11 @@ static int find_common(struct fetch_pack_args *args, @@ -346,11 +346,11 @@ static int find_common(struct fetch_pack_args *args,
state_len = req_buf.len;

if (args->depth > 0) {
char line[1024];
char *line;
unsigned char sha1[20];

send_request(args, fd[1], &req_buf);
while (packet_read_line(fd[0], line, sizeof(line))) {
while ((line = packet_read_line(fd[0], NULL))) {
if (!prefixcmp(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);

8
http-backend.c

@ -70,7 +70,7 @@ static void format_write(int fd, const char *fmt, ...) @@ -70,7 +70,7 @@ static void format_write(int fd, const char *fmt, ...)
if (n >= sizeof(buffer))
die("protocol error: impossibly long line");

safe_write(fd, buffer, n);
write_or_die(fd, buffer, n);
}

static void http_status(unsigned code, const char *msg)
@ -111,7 +111,7 @@ static void hdr_cache_forever(void) @@ -111,7 +111,7 @@ static void hdr_cache_forever(void)

static void end_headers(void)
{
safe_write(1, "\r\n", 2);
write_or_die(1, "\r\n", 2);
}

__attribute__((format (printf, 1, 2)))
@ -157,7 +157,7 @@ static void send_strbuf(const char *type, struct strbuf *buf) @@ -157,7 +157,7 @@ static void send_strbuf(const char *type, struct strbuf *buf)
hdr_int(content_length, buf->len);
hdr_str(content_type, type);
end_headers();
safe_write(1, buf->buf, buf->len);
write_or_die(1, buf->buf, buf->len);
}

static void send_local_file(const char *the_type, const char *name)
@ -185,7 +185,7 @@ static void send_local_file(const char *the_type, const char *name) @@ -185,7 +185,7 @@ static void send_local_file(const char *the_type, const char *name)
die_errno("Cannot read '%s'", p);
if (!n)
break;
safe_write(1, buf, n);
write_or_die(1, buf, n);
}
close(fd);
free(buf);

1
http.c

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
#include "url.h"
#include "credential.h"
#include "version.h"
#include "pkt-line.h"

int active_requests;
int http_is_verbose;

125
pkt-line.c

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
#include "cache.h"
#include "pkt-line.h"

char packet_buffer[LARGE_PACKET_MAX];
static const char *packet_trace_prefix = "git";
static const char trace_key[] = "GIT_TRACE_PACKET";

@ -46,38 +47,6 @@ static void packet_trace(const char *buf, unsigned int len, int write) @@ -46,38 +47,6 @@ static void packet_trace(const char *buf, unsigned int len, int write)
strbuf_release(&out);
}

/*
* Write a packetized stream, where each line is preceded by
* its length (including the header) as a 4-byte hex number.
* A length of 'zero' means end of stream (and a length of 1-3
* would be an error).
*
* This is all pretty stupid, but we use this packetized line
* format to make a streaming format possible without ever
* over-running the read buffers. That way we'll never read
* into what might be the pack data (which should go to another
* process entirely).
*
* The writing side could use stdio, but since the reading
* side can't, we stay with pure read/write interfaces.
*/
ssize_t safe_write(int fd, const void *buf, ssize_t n)
{
ssize_t nn = n;
while (n) {
int ret = xwrite(fd, buf, n);
if (ret > 0) {
buf = (char *) buf + ret;
n -= ret;
continue;
}
if (!ret)
die("write error (disk full?)");
die_errno("write error");
}
return nn;
}

/*
* If we buffered things up above (we don't, but we should),
* we'd flush it here
@ -85,7 +54,7 @@ ssize_t safe_write(int fd, const void *buf, ssize_t n) @@ -85,7 +54,7 @@ ssize_t safe_write(int fd, const void *buf, ssize_t n)
void packet_flush(int fd)
{
packet_trace("0000", 4, 1);
safe_write(fd, "0000", 4);
write_or_die(fd, "0000", 4);
}

void packet_buf_flush(struct strbuf *buf)
@ -121,7 +90,7 @@ void packet_write(int fd, const char *fmt, ...) @@ -121,7 +90,7 @@ void packet_write(int fd, const char *fmt, ...)
va_start(args, fmt);
n = format_packet(fmt, args);
va_end(args);
safe_write(fd, buffer, n);
write_or_die(fd, buffer, n);
}

void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
@ -135,13 +104,29 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...) @@ -135,13 +104,29 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
strbuf_add(buf, buffer, n);
}

static int safe_read(int fd, void *buffer, unsigned size, int return_line_fail)
static int get_packet_data(int fd, char **src_buf, size_t *src_size,
void *dst, unsigned size, int options)
{
ssize_t ret = read_in_full(fd, buffer, size);
if (ret < 0)
die_errno("read error");
else if (ret < size) {
if (return_line_fail)
ssize_t ret;

if (fd >= 0 && src_buf && *src_buf)
die("BUG: multiple sources given to packet_read");

/* Read up to "size" bytes from our source, whatever it is. */
if (src_buf && *src_buf) {
ret = size < *src_size ? size : *src_size;
memcpy(dst, *src_buf, ret);
*src_buf += ret;
*src_size -= ret;
} else {
ret = read_in_full(fd, dst, size);
if (ret < 0)
die_errno("read error");
}

/* And complain if we didn't get enough bytes to satisfy the read. */
if (ret < size) {
if (options & PACKET_READ_GENTLE_ON_EOF)
return -1;

die("The remote end hung up unexpectedly");
@ -175,13 +160,14 @@ static int packet_length(const char *linelen) @@ -175,13 +160,14 @@ static int packet_length(const char *linelen)
return len;
}

static int packet_read_internal(int fd, char *buffer, unsigned size, int return_line_fail)
int packet_read(int fd, char **src_buf, size_t *src_len,
char *buffer, unsigned size, int options)
{
int len, ret;
char linelen[4];

ret = safe_read(fd, linelen, 4, return_line_fail);
if (return_line_fail && ret < 0)
ret = get_packet_data(fd, src_buf, src_len, linelen, 4, options);
if (ret < 0)
return ret;
len = packet_length(linelen);
if (len < 0)
@ -193,50 +179,37 @@ static int packet_read_internal(int fd, char *buffer, unsigned size, int return_ @@ -193,50 +179,37 @@ static int packet_read_internal(int fd, char *buffer, unsigned size, int return_
len -= 4;
if (len >= size)
die("protocol error: bad line length %d", len);
ret = safe_read(fd, buffer, len, return_line_fail);
if (return_line_fail && ret < 0)
ret = get_packet_data(fd, src_buf, src_len, buffer, len, options);
if (ret < 0)
return ret;

if ((options & PACKET_READ_CHOMP_NEWLINE) &&
len && buffer[len-1] == '\n')
len--;

buffer[len] = 0;
packet_trace(buffer, len, 0);
return len;
}

int packet_read(int fd, char *buffer, unsigned size)
static char *packet_read_line_generic(int fd,
char **src, size_t *src_len,
int *dst_len)
{
return packet_read_internal(fd, buffer, size, 1);
int len = packet_read(fd, src, src_len,
packet_buffer, sizeof(packet_buffer),
PACKET_READ_CHOMP_NEWLINE);
if (dst_len)
*dst_len = len;
return len ? packet_buffer : NULL;
}

int packet_read_line(int fd, char *buffer, unsigned size)
char *packet_read_line(int fd, int *len_p)
{
return packet_read_internal(fd, buffer, size, 0);
return packet_read_line_generic(fd, NULL, NULL, len_p);
}

int packet_get_line(struct strbuf *out,
char **src_buf, size_t *src_len)
char *packet_read_line_buf(char **src, size_t *src_len, int *dst_len)
{
int len;

if (*src_len < 4)
return -1;
len = packet_length(*src_buf);
if (len < 0)
return -1;
if (!len) {
*src_buf += 4;
*src_len -= 4;
packet_trace("0000", 4, 0);
return 0;
}
if (*src_len < len)
return -2;

*src_buf += 4;
*src_len -= 4;
len -= 4;

strbuf_add(out, *src_buf, len);
*src_buf += len;
*src_len -= len;
packet_trace(out->buf, out->len, 0);
return len;
return packet_read_line_generic(-1, src, src_len, dst_len);
}

72
pkt-line.h

@ -5,16 +5,78 @@ @@ -5,16 +5,78 @@
#include "strbuf.h"

/*
* Silly packetized line writing interface
* Write a packetized stream, where each line is preceded by
* its length (including the header) as a 4-byte hex number.
* A length of 'zero' means end of stream (and a length of 1-3
* would be an error).
*
* This is all pretty stupid, but we use this packetized line
* format to make a streaming format possible without ever
* over-running the read buffers. That way we'll never read
* into what might be the pack data (which should go to another
* process entirely).
*
* The writing side could use stdio, but since the reading
* side can't, we stay with pure read/write interfaces.
*/
void packet_flush(int fd);
void packet_write(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
void packet_buf_flush(struct strbuf *buf);
void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3)));

int packet_read_line(int fd, char *buffer, unsigned size);
int packet_read(int fd, char *buffer, unsigned size);
int packet_get_line(struct strbuf *out, char **src_buf, size_t *src_len);
ssize_t safe_write(int, const void *, ssize_t);
/*
* Read a packetized line into the buffer, which must be at least size bytes
* long. The return value specifies the number of bytes read into the buffer.
*
* If src_buffer is not NULL (and nor is *src_buffer), it should point to a
* buffer containing the packet data to parse, of at least *src_len bytes.
* After the function returns, src_buf will be incremented and src_len
* decremented by the number of bytes consumed.
*
* If src_buffer (or *src_buffer) is NULL, then data is read from the
* descriptor "fd".
*
* If options does not contain PACKET_READ_GENTLE_ON_EOF, we will die under any
* of the following conditions:
*
* 1. Read error from descriptor.
*
* 2. Protocol error from the remote (e.g., bogus length characters).
*
* 3. Receiving a packet larger than "size" bytes.
*
* 4. Truncated output from the remote (e.g., we expected a packet but got
* EOF, or we got a partial packet followed by EOF).
*
* If options does contain PACKET_READ_GENTLE_ON_EOF, we will not die on
* condition 4 (truncated input), but instead return -1. However, we will still
* die for the other 3 conditions.
*
* If options contains PACKET_READ_CHOMP_NEWLINE, a trailing newline (if
* present) is removed from the buffer before returning.
*/
#define PACKET_READ_GENTLE_ON_EOF (1u<<0)
#define PACKET_READ_CHOMP_NEWLINE (1u<<1)
int packet_read(int fd, char **src_buffer, size_t *src_len, char
*buffer, unsigned size, int options);

/*
* Convenience wrapper for packet_read that is not gentle, and sets the
* CHOMP_NEWLINE option. The return value is NULL for a flush packet,
* and otherwise points to a static buffer (that may be overwritten by
* subsequent calls). If the size parameter is not NULL, the length of the
* packet is written to it.
*/
char *packet_read_line(int fd, int *size);

/*
* Same as packet_read_line, but read from a buf rather than a descriptor;
* see packet_read for details on how src_* is used.
*/
char *packet_read_line_buf(char **src_buf, size_t *src_len, int *size);

#define DEFAULT_PACKET_MAX 1000
#define LARGE_PACKET_MAX 65520
extern char packet_buffer[LARGE_PACKET_MAX];

#endif

188
remote-curl.c

@ -76,21 +76,82 @@ struct discovery { @@ -76,21 +76,82 @@ struct discovery {
char *buf_alloc;
char *buf;
size_t len;
struct ref *refs;
unsigned proto_git : 1;
};
static struct discovery *last_discovery;

static struct ref *parse_git_refs(struct discovery *heads, int for_push)
{
struct ref *list = NULL;
get_remote_heads(-1, heads->buf, heads->len, &list,
for_push ? REF_NORMAL : 0, NULL);
return list;
}

static struct ref *parse_info_refs(struct discovery *heads)
{
char *data, *start, *mid;
char *ref_name;
int i = 0;

struct ref *refs = NULL;
struct ref *ref = NULL;
struct ref *last_ref = NULL;

data = heads->buf;
start = NULL;
mid = data;
while (i < heads->len) {
if (!start) {
start = &data[i];
}
if (data[i] == '\t')
mid = &data[i];
if (data[i] == '\n') {
if (mid - start != 40)
die("%sinfo/refs not valid: is this a git repository?", url);
data[i] = 0;
ref_name = mid + 1;
ref = xmalloc(sizeof(struct ref) +
strlen(ref_name) + 1);
memset(ref, 0, sizeof(struct ref));
strcpy(ref->name, ref_name);
get_sha1_hex(start, ref->old_sha1);
if (!refs)
refs = ref;
if (last_ref)
last_ref->next = ref;
last_ref = ref;
start = NULL;
}
i++;
}

ref = alloc_ref("HEAD");
if (!http_fetch_ref(url, ref) &&
!resolve_remote_symref(ref, refs)) {
ref->next = refs;
refs = ref;
} else {
free(ref);
}

return refs;
}

static void free_discovery(struct discovery *d)
{
if (d) {
if (d == last_discovery)
last_discovery = NULL;
free(d->buf_alloc);
free_refs(d->refs);
free(d);
}
}

static struct discovery* discover_refs(const char *service)
static struct discovery* discover_refs(const char *service, int for_push)
{
struct strbuf exp = STRBUF_INIT;
struct strbuf type = STRBUF_INIT;
@ -138,32 +199,35 @@ static struct discovery* discover_refs(const char *service) @@ -138,32 +199,35 @@ static struct discovery* discover_refs(const char *service)
if (maybe_smart &&
(5 <= last->len && last->buf[4] == '#') &&
!strbuf_cmp(&exp, &type)) {
char *line;

/*
* smart HTTP response; validate that the service
* pkt-line matches our request.
*/
if (packet_get_line(&buffer, &last->buf, &last->len) <= 0)
die("%s has invalid packet header", refs_url);
if (buffer.len && buffer.buf[buffer.len - 1] == '\n')
strbuf_setlen(&buffer, buffer.len - 1);
line = packet_read_line_buf(&last->buf, &last->len, NULL);

strbuf_reset(&exp);
strbuf_addf(&exp, "# service=%s", service);
if (strbuf_cmp(&exp, &buffer))
die("invalid server response; got '%s'", buffer.buf);
if (strcmp(line, exp.buf))
die("invalid server response; got '%s'", line);
strbuf_release(&exp);

/* The header can include additional metadata lines, up
* until a packet flush marker. Ignore these now, but
* in the future we might start to scan them.
*/
strbuf_reset(&buffer);
while (packet_get_line(&buffer, &last->buf, &last->len) > 0)
strbuf_reset(&buffer);
while (packet_read_line_buf(&last->buf, &last->len, NULL))
;

last->proto_git = 1;
}

if (last->proto_git)
last->refs = parse_git_refs(last, for_push);
else
last->refs = parse_info_refs(last);

free(refs_url);
strbuf_release(&exp);
strbuf_release(&type);
@ -172,99 +236,16 @@ static struct discovery* discover_refs(const char *service) @@ -172,99 +236,16 @@ static struct discovery* discover_refs(const char *service)
return last;
}

static int write_discovery(int in, int out, void *data)
{
struct discovery *heads = data;
int err = 0;
if (write_in_full(out, heads->buf, heads->len) != heads->len)
err = 1;
close(out);
return err;
}

static struct ref *parse_git_refs(struct discovery *heads, int for_push)
{
struct ref *list = NULL;
struct async async;

memset(&async, 0, sizeof(async));
async.proc = write_discovery;
async.data = heads;
async.out = -1;

if (start_async(&async))
die("cannot start thread to parse advertised refs");
get_remote_heads(async.out, &list,
for_push ? REF_NORMAL : 0, NULL);
close(async.out);
if (finish_async(&async))
die("ref parsing thread failed");
return list;
}

static struct ref *parse_info_refs(struct discovery *heads)
{
char *data, *start, *mid;
char *ref_name;
int i = 0;

struct ref *refs = NULL;
struct ref *ref = NULL;
struct ref *last_ref = NULL;

data = heads->buf;
start = NULL;
mid = data;
while (i < heads->len) {
if (!start) {
start = &data[i];
}
if (data[i] == '\t')
mid = &data[i];
if (data[i] == '\n') {
if (mid - start != 40)
die("%sinfo/refs not valid: is this a git repository?", url);
data[i] = 0;
ref_name = mid + 1;
ref = xmalloc(sizeof(struct ref) +
strlen(ref_name) + 1);
memset(ref, 0, sizeof(struct ref));
strcpy(ref->name, ref_name);
get_sha1_hex(start, ref->old_sha1);
if (!refs)
refs = ref;
if (last_ref)
last_ref->next = ref;
last_ref = ref;
start = NULL;
}
i++;
}

ref = alloc_ref("HEAD");
if (!http_fetch_ref(url, ref) &&
!resolve_remote_symref(ref, refs)) {
ref->next = refs;
refs = ref;
} else {
free(ref);
}

return refs;
}

static struct ref *get_refs(int for_push)
{
struct discovery *heads;

if (for_push)
heads = discover_refs("git-receive-pack");
heads = discover_refs("git-receive-pack", for_push);
else
heads = discover_refs("git-upload-pack");
heads = discover_refs("git-upload-pack", for_push);

if (heads->proto_git)
return parse_git_refs(heads, for_push);
return parse_info_refs(heads);
return heads->refs;
}

static void output_refs(struct ref *refs)
@ -278,7 +259,6 @@ static void output_refs(struct ref *refs) @@ -278,7 +259,6 @@ static void output_refs(struct ref *refs)
}
printf("\n");
fflush(stdout);
free_refs(refs);
}

struct rpc_state {
@ -308,7 +288,7 @@ static size_t rpc_out(void *ptr, size_t eltsize, @@ -308,7 +288,7 @@ static size_t rpc_out(void *ptr, size_t eltsize,

if (!avail) {
rpc->initial_buffer = 0;
avail = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
avail = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
if (!avail)
return 0;
rpc->pos = 0;
@ -425,7 +405,7 @@ static int post_rpc(struct rpc_state *rpc) @@ -425,7 +405,7 @@ static int post_rpc(struct rpc_state *rpc)
break;
}

n = packet_read_line(rpc->out, buf, left);
n = packet_read(rpc->out, NULL, NULL, buf, left, 0);
if (!n)
break;
rpc->len += n;
@ -579,7 +559,7 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads) @@ -579,7 +559,7 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
rpc->hdr_accept = strbuf_detach(&buf, NULL);

while (!err) {
int n = packet_read_line(rpc->out, rpc->buf, rpc->alloc);
int n = packet_read(rpc->out, NULL, NULL, rpc->buf, rpc->alloc, 0);
if (!n)
break;
rpc->pos = 0;
@ -685,7 +665,7 @@ static int fetch_git(struct discovery *heads, @@ -685,7 +665,7 @@ static int fetch_git(struct discovery *heads,

err = rpc_service(&rpc, heads);
if (rpc.result.len)
safe_write(1, rpc.result.buf, rpc.result.len);
write_or_die(1, rpc.result.buf, rpc.result.len);
strbuf_release(&rpc.result);
strbuf_release(&preamble);
free(depth_arg);
@ -694,7 +674,7 @@ static int fetch_git(struct discovery *heads, @@ -694,7 +674,7 @@ static int fetch_git(struct discovery *heads,

static int fetch(int nr_heads, struct ref **to_fetch)
{
struct discovery *d = discover_refs("git-upload-pack");
struct discovery *d = discover_refs("git-upload-pack", 0);
if (d->proto_git)
return fetch_git(d, nr_heads, to_fetch);
else
@ -805,7 +785,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) @@ -805,7 +785,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)

err = rpc_service(&rpc, heads);
if (rpc.result.len)
safe_write(1, rpc.result.buf, rpc.result.len);
write_or_die(1, rpc.result.buf, rpc.result.len);
strbuf_release(&rpc.result);
free(argv);
return err;
@ -813,7 +793,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) @@ -813,7 +793,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)

static int push(int nr_spec, char **specs)
{
struct discovery *heads = discover_refs("git-receive-pack");
struct discovery *heads = discover_refs("git-receive-pack", 1);
int ret;

if (heads->proto_git)

22
send-pack.c

@ -106,15 +106,11 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext @@ -106,15 +106,11 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
static int receive_status(int in, struct ref *refs)
{
struct ref *hint;
char line[1000];
int ret = 0;
int len = packet_read_line(in, line, sizeof(line));
if (len < 10 || memcmp(line, "unpack ", 7))
char *line = packet_read_line(in, NULL);
if (prefixcmp(line, "unpack "))
return error("did not receive remote status");
if (memcmp(line, "unpack ok\n", 10)) {
char *p = line + strlen(line) - 1;
if (*p == '\n')
*p = '\0';
if (strcmp(line, "unpack ok")) {
error("unpack failed: %s", line + 7);
ret = -1;
}
@ -122,17 +118,15 @@ static int receive_status(int in, struct ref *refs) @@ -122,17 +118,15 @@ static int receive_status(int in, struct ref *refs)
while (1) {
char *refname;
char *msg;
len = packet_read_line(in, line, sizeof(line));
if (!len)
line = packet_read_line(in, NULL);
if (!line)
break;
if (len < 3 ||
(memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
fprintf(stderr, "protocol error: %s\n", line);
if (prefixcmp(line, "ok ") && prefixcmp(line, "ng ")) {
error("invalid ref status from remote: %s", line);
ret = -1;
break;
}

line[strlen(line)-1] = '\0';
refname = line + 3;
msg = strchr(refname, ' ');
if (msg)
@ -281,7 +275,7 @@ int send_pack(struct send_pack_args *args, @@ -281,7 +275,7 @@ int send_pack(struct send_pack_args *args,
send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
}
} else {
safe_write(out, req_buf.buf, req_buf.len);
write_or_die(out, req_buf.buf, req_buf.len);
packet_flush(out);
}
strbuf_release(&req_buf);

11
sideband.c

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
#include "cache.h"
#include "pkt-line.h"
#include "sideband.h"

@ -37,7 +38,7 @@ int recv_sideband(const char *me, int in_stream, int out) @@ -37,7 +38,7 @@ int recv_sideband(const char *me, int in_stream, int out)

while (1) {
int band, len;
len = packet_read_line(in_stream, buf + pf, LARGE_PACKET_MAX);
len = packet_read(in_stream, NULL, NULL, buf + pf, LARGE_PACKET_MAX, 0);
if (len == 0)
break;
if (len < 1) {
@ -108,7 +109,7 @@ int recv_sideband(const char *me, int in_stream, int out) @@ -108,7 +109,7 @@ int recv_sideband(const char *me, int in_stream, int out)
} while (len);
continue;
case 1:
safe_write(out, buf + pf+1, len);
write_or_die(out, buf + pf+1, len);
continue;
default:
fprintf(stderr, "%s: protocol error: bad band #%d\n",
@ -138,12 +139,12 @@ ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet @@ -138,12 +139,12 @@ ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet
if (0 <= band) {
sprintf(hdr, "%04x", n + 5);
hdr[4] = band;
safe_write(fd, hdr, 5);
write_or_die(fd, hdr, 5);
} else {
sprintf(hdr, "%04x", n + 4);
safe_write(fd, hdr, 4);
write_or_die(fd, hdr, 4);
}
safe_write(fd, p, n);
write_or_die(fd, p, n);
p += n;
sz -= n;
}

3
sideband.h

@ -4,9 +4,6 @@ @@ -4,9 +4,6 @@
#define SIDEBAND_PROTOCOL_ERROR -2
#define SIDEBAND_REMOTE_ERROR -1

#define DEFAULT_PACKET_MAX 1000
#define LARGE_PACKET_MAX 65520

int recv_sideband(const char *me, int in_stream, int out);
ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max);


64
t/t5503-tagfollow.sh

@ -4,10 +4,6 @@ test_description='test automatic tag following' @@ -4,10 +4,6 @@ test_description='test automatic tag following'

. ./test-lib.sh

if ! test_have_prereq NOT_MINGW; then
say "GIT_DEBUG_SEND_PACK not supported - skipping tests"
fi

# End state of the repository:
#
# T - tag1 S - tag2
@ -17,7 +13,7 @@ fi @@ -17,7 +13,7 @@ fi
# \ C - origin/cat \
# origin/master master

test_expect_success NOT_MINGW setup '
test_expect_success setup '
test_tick &&
echo ichi >file &&
git add file &&
@ -39,28 +35,35 @@ test_expect_success NOT_MINGW setup ' @@ -39,28 +35,35 @@ test_expect_success NOT_MINGW setup '
'

U=UPLOAD_LOG
UPATH="$(pwd)/$U"

test_expect_success NOT_MINGW 'setup expect' '
test_expect_success 'setup expect' '
cat - <<EOF >expect
#S
want $A
#E
EOF
'

test_expect_success NOT_MINGW 'fetch A (new commit : 1 connection)' '
get_needs () {
test -s "$1" &&
perl -alne '
next unless $F[1] eq "upload-pack<";
last if $F[2] eq "0000";
print $F[2], " ", $F[3];
' "$1"
}

test_expect_success 'fetch A (new commit : 1 connection)' '
rm -f $U &&
(
cd cloned &&
GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
GIT_TRACE_PACKET=$UPATH git fetch &&
test $A = $(git rev-parse --verify origin/master)
) &&
test -s $U &&
cut -d" " -f1,2 $U >actual &&
get_needs $U >actual &&
test_cmp expect actual
'

test_expect_success NOT_MINGW "create tag T on A, create C on branch cat" '
test_expect_success "create tag T on A, create C on branch cat" '
git tag -a -m tag1 tag1 $A &&
T=$(git rev-parse --verify tag1) &&

@ -72,30 +75,27 @@ test_expect_success NOT_MINGW "create tag T on A, create C on branch cat" ' @@ -72,30 +75,27 @@ test_expect_success NOT_MINGW "create tag T on A, create C on branch cat" '
git checkout master
'

test_expect_success NOT_MINGW 'setup expect' '
test_expect_success 'setup expect' '
cat - <<EOF >expect
#S
want $C
want $T
#E
EOF
'

test_expect_success NOT_MINGW 'fetch C, T (new branch, tag : 1 connection)' '
test_expect_success 'fetch C, T (new branch, tag : 1 connection)' '
rm -f $U &&
(
cd cloned &&
GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
GIT_TRACE_PACKET=$UPATH git fetch &&
test $C = $(git rev-parse --verify origin/cat) &&
test $T = $(git rev-parse --verify tag1) &&
test $A = $(git rev-parse --verify tag1^0)
) &&
test -s $U &&
cut -d" " -f1,2 $U >actual &&
get_needs $U >actual &&
test_cmp expect actual
'

test_expect_success NOT_MINGW "create commits O, B, tag S on B" '
test_expect_success "create commits O, B, tag S on B" '
test_tick &&
echo O >file &&
git add file &&
@ -111,39 +111,34 @@ test_expect_success NOT_MINGW "create commits O, B, tag S on B" ' @@ -111,39 +111,34 @@ test_expect_success NOT_MINGW "create commits O, B, tag S on B" '
S=$(git rev-parse --verify tag2)
'

test_expect_success NOT_MINGW 'setup expect' '
test_expect_success 'setup expect' '
cat - <<EOF >expect
#S
want $B
want $S
#E
EOF
'

test_expect_success NOT_MINGW 'fetch B, S (commit and tag : 1 connection)' '
test_expect_success 'fetch B, S (commit and tag : 1 connection)' '
rm -f $U &&
(
cd cloned &&
GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
GIT_TRACE_PACKET=$UPATH git fetch &&
test $B = $(git rev-parse --verify origin/master) &&
test $B = $(git rev-parse --verify tag2^0) &&
test $S = $(git rev-parse --verify tag2)
) &&
test -s $U &&
cut -d" " -f1,2 $U >actual &&
get_needs $U >actual &&
test_cmp expect actual
'

test_expect_success NOT_MINGW 'setup expect' '
test_expect_success 'setup expect' '
cat - <<EOF >expect
#S
want $B
want $S
#E
EOF
'

test_expect_success NOT_MINGW 'new clone fetch master and tags' '
test_expect_success 'new clone fetch master and tags' '
git branch -D cat
rm -f $U
(
@ -151,15 +146,14 @@ test_expect_success NOT_MINGW 'new clone fetch master and tags' ' @@ -151,15 +146,14 @@ test_expect_success NOT_MINGW 'new clone fetch master and tags' '
cd clone2 &&
git init &&
git remote add origin .. &&
GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
GIT_TRACE_PACKET=$UPATH git fetch &&
test $B = $(git rev-parse --verify origin/master) &&
test $S = $(git rev-parse --verify tag2) &&
test $B = $(git rev-parse --verify tag2^0) &&
test $T = $(git rev-parse --verify tag1) &&
test $A = $(git rev-parse --verify tag1^0)
) &&
test -s $U &&
cut -d" " -f1,2 $U >actual &&
get_needs $U >actual &&
test_cmp expect actual
'


18
t/t5700-clone-reference.sh

@ -54,11 +54,14 @@ cd "$base_dir" @@ -54,11 +54,14 @@ cd "$base_dir"

rm -f "$U.D"

test_expect_success 'cloning with reference (no -l -s)' \
'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U.D"'
test_expect_success 'cloning with reference (no -l -s)' '
GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D
'

test_expect_success 'fetched no objects' \
'! grep "^want" "$U.D"'
test_expect_success 'fetched no objects' '
test -s "$U.D" &&
! grep " want" "$U.D"
'

cd "$base_dir"

@ -173,12 +176,13 @@ test_expect_success 'fetch with incomplete alternates' ' @@ -173,12 +176,13 @@ test_expect_success 'fetch with incomplete alternates' '
(
cd K &&
git remote add J "file://$base_dir/J" &&
GIT_DEBUG_SEND_PACK=3 git fetch J 3>"$U.K"
GIT_TRACE_PACKET=$U.K git fetch J
) &&
master_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/master) &&
! grep "^want $master_object" "$U.K" &&
test -s "$U.K" &&
! grep " want $master_object" "$U.K" &&
tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) &&
! grep "^want $tag_object" "$U.K"
! grep " want $tag_object" "$U.K"
'

test_done

6
transport.c

@ -508,7 +508,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus @@ -508,7 +508,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
struct ref *refs;

connect_setup(transport, for_push, 0);
get_remote_heads(data->fd[0], &refs,
get_remote_heads(data->fd[0], NULL, 0, &refs,
for_push ? REF_NORMAL : 0, &data->extra_have);
data->got_remote_heads = 1;

@ -537,7 +537,7 @@ static int fetch_refs_via_pack(struct transport *transport, @@ -537,7 +537,7 @@ static int fetch_refs_via_pack(struct transport *transport,

if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL);
get_remote_heads(data->fd[0], NULL, 0, &refs_tmp, 0, NULL);
data->got_remote_heads = 1;
}

@ -795,7 +795,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re @@ -795,7 +795,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
struct ref *tmp_refs;
connect_setup(transport, 1, 0);

get_remote_heads(data->fd[0], &tmp_refs, REF_NORMAL, NULL);
get_remote_heads(data->fd[0], NULL, 0, &tmp_refs, REF_NORMAL, NULL);
data->got_remote_heads = 1;
}


40
upload-pack.c

@ -44,7 +44,6 @@ static unsigned int timeout; @@ -44,7 +44,6 @@ static unsigned int timeout;
* otherwise maximum packet size (up to 65520 bytes).
*/
static int use_sideband;
static int debug_fd;
static int advertise_refs;
static int stateless_rpc;

@ -53,13 +52,6 @@ static void reset_timeout(void) @@ -53,13 +52,6 @@ static void reset_timeout(void)
alarm(timeout);
}

static int strip(char *line, int len)
{
if (len && line[len-1] == '\n')
line[--len] = 0;
return len;
}

static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
{
if (use_sideband)
@ -72,7 +64,8 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz) @@ -72,7 +64,8 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
xwrite(fd, data, sz);
return sz;
}
return safe_write(fd, data, sz);
write_or_die(fd, data, sz);
return sz;
}

static FILE *pack_pipe = NULL;
@ -415,7 +408,6 @@ static int ok_to_give_up(void) @@ -415,7 +408,6 @@ static int ok_to_give_up(void)

static int get_common_commits(void)
{
static char line[1000];
unsigned char sha1[20];
char last_hex[41];
int got_common = 0;
@ -425,10 +417,10 @@ static int get_common_commits(void) @@ -425,10 +417,10 @@ static int get_common_commits(void)
save_commit_buffer = 0;

for (;;) {
int len = packet_read_line(0, line, sizeof(line));
char *line = packet_read_line(0, NULL);
reset_timeout();

if (!len) {
if (!line) {
if (multi_ack == 2 && got_common
&& !got_other && ok_to_give_up()) {
sent_ready = 1;
@ -447,7 +439,6 @@ static int get_common_commits(void) @@ -447,7 +439,6 @@ static int get_common_commits(void)
got_other = 0;
continue;
}
strip(line, len);
if (!prefixcmp(line, "have ")) {
switch (got_sha1(line+5, sha1)) {
case -1: /* they have what we do not */
@ -581,36 +572,33 @@ error: @@ -581,36 +572,33 @@ error:
static void receive_needs(void)
{
struct object_array shallows = OBJECT_ARRAY_INIT;
static char line[1000];
int len, depth = 0;
int depth = 0;
int has_non_tip = 0;

shallow_nr = 0;
if (debug_fd)
write_str_in_full(debug_fd, "#S\n");
for (;;) {
struct object *o;
const char *features;
unsigned char sha1_buf[20];
len = packet_read_line(0, line, sizeof(line));
char *line = packet_read_line(0, NULL);
reset_timeout();
if (!len)
if (!line)
break;
if (debug_fd)
write_in_full(debug_fd, line, len);

if (!prefixcmp(line, "shallow ")) {
unsigned char sha1[20];
struct object *object;
if (get_sha1(line + 8, sha1))
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
object = parse_object(sha1);
if (!object)
die("did not find object for %s", line);
if (object->type != OBJ_COMMIT)
die("invalid shallow object %s", sha1_to_hex(sha1));
object->flags |= CLIENT_SHALLOW;
add_object_array(object, NULL, &shallows);
if (!(object->flags & CLIENT_SHALLOW)) {
object->flags |= CLIENT_SHALLOW;
add_object_array(object, NULL, &shallows);
}
continue;
}
if (!prefixcmp(line, "deepen ")) {
@ -657,8 +645,6 @@ static void receive_needs(void) @@ -657,8 +645,6 @@ static void receive_needs(void)
add_object_array(o, NULL, &want_obj);
}
}
if (debug_fd)
write_str_in_full(debug_fd, "#E\n");

/*
* We have sent all our refs already, and the other end
@ -854,8 +840,6 @@ int main(int argc, char **argv) @@ -854,8 +840,6 @@ int main(int argc, char **argv)
if (is_repository_shallow())
die("attempt to fetch/clone from a shallow repository");
git_config(upload_pack_config, NULL);
if (getenv("GIT_DEBUG_SEND_PACK"))
debug_fd = atoi(getenv("GIT_DEBUG_SEND_PACK"));
upload_pack();
return 0;
}

19
write_or_die.c

@ -1,5 +1,15 @@ @@ -1,5 +1,15 @@
#include "cache.h"

static void check_pipe(int err)
{
if (err == EPIPE) {
signal(SIGPIPE, SIG_DFL);
raise(SIGPIPE);
/* Should never happen, but just in case... */
exit(141);
}
}

/*
* Some cases use stdio, but want to flush after the write
* to get error handling (and to get better interactive
@ -34,8 +44,7 @@ void maybe_flush_or_die(FILE *f, const char *desc) @@ -34,8 +44,7 @@ void maybe_flush_or_die(FILE *f, const char *desc)
return;
}
if (fflush(f)) {
if (errno == EPIPE)
exit(0);
check_pipe(errno);
die_errno("write failure on '%s'", desc);
}
}
@ -50,8 +59,7 @@ void fsync_or_die(int fd, const char *msg) @@ -50,8 +59,7 @@ void fsync_or_die(int fd, const char *msg)
void write_or_die(int fd, const void *buf, size_t count)
{
if (write_in_full(fd, buf, count) < 0) {
if (errno == EPIPE)
exit(0);
check_pipe(errno);
die_errno("write error");
}
}
@ -59,8 +67,7 @@ void write_or_die(int fd, const void *buf, size_t count) @@ -59,8 +67,7 @@ void write_or_die(int fd, const void *buf, size_t count)
int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
{
if (write_in_full(fd, buf, count) < 0) {
if (errno == EPIPE)
exit(0);
check_pipe(errno);
fprintf(stderr, "%s: write error (%s)\n",
msg, strerror(errno));
return 0;

Loading…
Cancel
Save