提交 e013bdab 编写于 作者: J Junio C Hamano

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
...@@ -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 *remote, const char *exec,
const char *name_hint) const char *name_hint)
{ {
char buf[LARGE_PACKET_MAX]; char *buf;
int fd[2], i, len, rv; int fd[2], i, rv;
struct transport *transport; struct transport *transport;
struct remote *_remote; 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_write(fd[1], "argument %s\n", argv[i]);
packet_flush(fd[1]); packet_flush(fd[1]);
len = packet_read_line(fd[0], buf, sizeof(buf)); buf = packet_read_line(fd[0], NULL);
if (!len) if (!buf)
die(_("git archive: expected ACK/NAK, got EOF")); die(_("git archive: expected ACK/NAK, got EOF"));
if (buf[len-1] == '\n')
buf[--len] = 0;
if (strcmp(buf, "ACK")) { if (strcmp(buf, "ACK")) {
if (len > 5 && !prefixcmp(buf, "NACK ")) if (!prefixcmp(buf, "NACK "))
die(_("git archive: NACK %s"), buf + 5); die(_("git archive: NACK %s"), buf + 5);
if (len > 4 && !prefixcmp(buf, "ERR ")) if (!prefixcmp(buf, "ERR "))
die(_("remote error: %s"), buf + 4); die(_("remote error: %s"), buf + 4);
die(_("git archive: protocol error")); die(_("git archive: protocol error"));
} }
len = packet_read_line(fd[0], buf, sizeof(buf)); if (packet_read_line(fd[0], NULL))
if (len)
die(_("git archive: expected a flush")); die(_("git archive: expected a flush"));
/* Now, start reading from fd[0] and spit it out to stdout */ /* Now, start reading from fd[0] and spit it out to stdout */
......
...@@ -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 /* in stateless RPC mode we use pkt-line to read
* from stdin, until we get a flush packet * from stdin, until we get a flush packet
*/ */
static char line[1000];
for (;;) { for (;;) {
int n = packet_read_line(0, line, sizeof(line)); char *line = packet_read_line(0, NULL);
if (!n) if (!line)
break; break;
if (line[n-1] == '\n') add_sought_entry(&sought, &nr_sought, &alloc_sought, line);
n--;
add_sought_entry_mem(&sought, &nr_sought, &alloc_sought, line, n);
} }
} }
else { 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); 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, ref = fetch_pack(&args, fd, conn, ref, dest,
sought, nr_sought, pack_lockfile_ptr); sought, nr_sought, pack_lockfile_ptr);
......
...@@ -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 *commands = NULL;
struct command **p = &commands; struct command **p = &commands;
for (;;) { for (;;) {
static char line[1000]; char *line;
unsigned char old_sha1[20], new_sha1[20]; unsigned char old_sha1[20], new_sha1[20];
struct command *cmd; struct command *cmd;
char *refname; char *refname;
int len, reflen; int len, reflen;
len = packet_read_line(0, line, sizeof(line)); line = packet_read_line(0, &len);
if (!len) if (!line)
break; break;
if (line[len-1] == '\n')
line[--len] = 0;
if (len < 83 || if (len < 83 ||
line[40] != ' ' || line[40] != ' ' ||
line[81] != ' ' || 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) if (use_sideband)
send_sideband(1, 1, buf.buf, buf.len, use_sideband); send_sideband(1, 1, buf.buf, buf.len, use_sideband);
else else
safe_write(1, buf.buf, buf.len); write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf); strbuf_release(&buf);
} }
......
...@@ -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'); strbuf_addch(&buf, '\n');
safe_write(1, buf.buf, buf.len); write_or_die(1, buf.buf, buf.len);
} }
strbuf_release(&buf); 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)); 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); transport_verify_remote_names(nr_refspecs, refspecs);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "pkt-line.h" #include "pkt-line.h"
#include "sideband.h" #include "sideband.h"
#include "run-command.h" #include "run-command.h"
#include "argv-array.h"
static const char upload_archive_usage[] = static const char upload_archive_usage[] =
"git upload-archive <repo>"; "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) 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 "; const char *arg_cmd = "argument ";
char *p, buf[4096];
int sent_argc;
int len;
if (argc != 2) if (argc != 2)
usage(upload_archive_usage); usage(upload_archive_usage);
if (strlen(argv[1]) + 1 > sizeof(buf)) if (!enter_repo(argv[1], 0))
die("insanely long repository name"); die("'%s' does not appear to be a git repository", argv[1]);
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);
/* put received options in sent_argv[] */ /* put received options in sent_argv[] */
sent_argc = 1; argv_array_push(&sent_argv, "git-upload-archive");
sent_argv[0] = "git-upload-archive"; for (;;) {
for (p = buf;;) { char *buf = packet_read_line(0, NULL);
/* This will die if not enough free space in buf */ if (!buf)
len = packet_read_line(0, p, (buf + sizeof buf) - p);
if (len == 0)
break; /* got a flush */ break; /* got a flush */
if (sent_argc > MAX_ARGS - 2) if (sent_argv.argc > MAX_ARGS)
die("Too many options (>%d)", MAX_ARGS - 2); die("Too many options (>%d)", MAX_ARGS - 1);
if (p[len-1] == '\n') { if (prefixcmp(buf, arg_cmd))
p[--len] = 0;
}
if (len < strlen(arg_cmd) ||
strncmp(arg_cmd, p, strlen(arg_cmd)))
die("'argument' token or flush expected"); die("'argument' token or flush expected");
argv_array_push(&sent_argv, buf + strlen(arg_cmd));
len -= strlen(arg_cmd);
memmove(p, p + strlen(arg_cmd), len);
sent_argv[sent_argc++] = p;
p += len;
*p++ = 0;
} }
sent_argv[sent_argc] = NULL;
/* parse all options sent by the client */ /* 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))) __attribute__((format (printf, 1, 2)))
......
...@@ -1064,7 +1064,9 @@ struct extra_have_objects { ...@@ -1064,7 +1064,9 @@ struct extra_have_objects {
int nr, alloc; int nr, alloc;
unsigned char (*array)[20]; 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 server_supports(const char *feature);
extern int parse_feature_request(const char *features, 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); extern const char *server_feature_value(const char *feature, int *len_ret);
......
...@@ -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 * Read all the refs from the other end
*/ */
struct ref **get_remote_heads(int in, struct ref **list, struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
unsigned int flags, struct ref **list, unsigned int flags,
struct extra_have_objects *extra_have) struct extra_have_objects *extra_have)
{ {
int got_at_least_one_head = 0; 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 (;;) { for (;;) {
struct ref *ref; struct ref *ref;
unsigned char old_sha1[20]; unsigned char old_sha1[20];
static char buffer[1000];
char *name; char *name;
int len, name_len; 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) if (len < 0)
die_initial_contact(got_at_least_one_head); die_initial_contact(got_at_least_one_head);
if (!len) if (!len)
break; break;
if (buffer[len-1] == '\n')
buffer[--len] = 0;
if (len > 4 && !prefixcmp(buffer, "ERR ")) if (len > 4 && !prefixcmp(buffer, "ERR "))
die("remote error: %s", buffer + 4); die("remote error: %s", buffer + 4);
......
...@@ -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 int execute(void)
{ {
static char line[1000]; char *line = packet_buffer;
int pktlen, len, i; int pktlen, len, i;
char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT"); 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); loginfo("Connection from %s:%s", addr, port);
alarm(init_timeout ? init_timeout : timeout); 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); alarm(0);
len = strlen(line); len = strlen(line);
......
...@@ -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 * shallow and unshallow commands every time there
* is a block of have lines exchanged. * is a block of have lines exchanged.
*/ */
char line[1000]; char *line;
while (packet_read_line(fd, line, sizeof(line))) { while ((line = packet_read_line(fd, NULL))) {
if (!prefixcmp(line, "shallow ")) if (!prefixcmp(line, "shallow "))
continue; continue;
if (!prefixcmp(line, "unshallow ")) 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 enum ack_type get_ack(int fd, unsigned char *result_sha1)
{ {
static char line[1000]; int len;
int len = packet_read_line(fd, line, sizeof(line)); char *line = packet_read_line(fd, &len);
if (!len) if (!len)
die("git fetch-pack: expected ACK/NAK, got EOF"); die("git fetch-pack: expected ACK/NAK, got EOF");
if (line[len-1] == '\n')
line[--len] = 0;
if (!strcmp(line, "NAK")) if (!strcmp(line, "NAK"))
return NAK; return NAK;
if (!prefixcmp(line, "ACK ")) { if (!prefixcmp(line, "ACK ")) {
if (!get_sha1_hex(line+4, result_sha1)) { if (!get_sha1_hex(line+4, result_sha1)) {
if (len < 45)
return ACK;
if (strstr(line+45, "continue")) if (strstr(line+45, "continue"))
return ACK_continue; return ACK_continue;
if (strstr(line+45, "common")) 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); send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
packet_flush(fd); packet_flush(fd);
} else } 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) 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; state_len = req_buf.len;
if (args->depth > 0) { if (args->depth > 0) {
char line[1024]; char *line;
unsigned char sha1[20]; unsigned char sha1[20];
send_request(args, fd[1], &req_buf); 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 (!prefixcmp(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1)) if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line); die("invalid shallow line: %s", line);
......
...@@ -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)) if (n >= sizeof(buffer))
die("protocol error: impossibly long line"); 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) 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) static void end_headers(void)
{ {
safe_write(1, "\r\n", 2); write_or_die(1, "\r\n", 2);
} }
__attribute__((format (printf, 1, 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_int(content_length, buf->len);
hdr_str(content_type, type); hdr_str(content_type, type);
end_headers(); 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) 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); die_errno("Cannot read '%s'", p);
if (!n) if (!n)
break; break;
safe_write(1, buf, n); write_or_die(1, buf, n);
} }
close(fd); close(fd);
free(buf); free(buf);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "url.h" #include "url.h"
#include "credential.h" #include "credential.h"
#include "version.h" #include "version.h"
#include "pkt-line.h"
int active_requests; int active_requests;
int http_is_verbose; int http_is_verbose;
......
#include "cache.h" #include "cache.h"
#include "pkt-line.h" #include "pkt-line.h"
char packet_buffer[LARGE_PACKET_MAX];
static const char *packet_trace_prefix = "git"; static const char *packet_trace_prefix = "git";
static const char trace_key[] = "GIT_TRACE_PACKET"; 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); 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), * If we buffered things up above (we don't, but we should),
* we'd flush it here * 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) void packet_flush(int fd)
{ {
packet_trace("0000", 4, 1); packet_trace("0000", 4, 1);
safe_write(fd, "0000", 4); write_or_die(fd, "0000", 4);
} }
void packet_buf_flush(struct strbuf *buf) 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); va_start(args, fmt);
n = format_packet(fmt, args); n = format_packet(fmt, args);
va_end(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, ...) 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); 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); ssize_t ret;
if (ret < 0)
die_errno("read error"); if (fd >= 0 && src_buf && *src_buf)
else if (ret < size) { die("BUG: multiple sources given to packet_read");
if (return_line_fail)
/* 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; return -1;
die("The remote end hung up unexpectedly"); 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; 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; int len, ret;
char linelen[4]; char linelen[4];
ret = safe_read(fd, linelen, 4, return_line_fail); ret = get_packet_data(fd, src_buf, src_len, linelen, 4, options);
if (return_line_fail && ret < 0) if (ret < 0)
return ret; return ret;
len = packet_length(linelen); len = packet_length(linelen);
if (len < 0) 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; len -= 4;
if (len >= size) if (len >= size)
die("protocol error: bad line length %d", len); die("protocol error: bad line length %d", len);
ret = safe_read(fd, buffer, len, return_line_fail); ret = get_packet_data(fd, src_buf, src_len, buffer, len, options);
if (return_line_fail && ret < 0) if (ret < 0)
return ret; return ret;
if ((options & PACKET_READ_CHOMP_NEWLINE) &&
len && buffer[len-1] == '\n')
len--;
buffer[len] = 0; buffer[len] = 0;
packet_trace(buffer, len, 0); packet_trace(buffer, len, 0);
return len; 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 *packet_read_line_buf(char **src, size_t *src_len, int *dst_len)
char **src_buf, size_t *src_len)
{ {
int len; return packet_read_line_generic(-1, src, src_len, dst_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;
} }
...@@ -5,16 +5,78 @@ ...@@ -5,16 +5,78 @@
#include "strbuf.h" #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_flush(int fd);
void packet_write(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3))); void packet_write(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
void packet_buf_flush(struct strbuf *buf); void packet_buf_flush(struct strbuf *buf);
void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3))); 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); * Read a packetized line into the buffer, which must be at least size bytes
int packet_get_line(struct strbuf *out, char **src_buf, size_t *src_len); * long. The return value specifies the number of bytes read into the buffer.
ssize_t safe_write(int, const void *, ssize_t); *
* 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 #endif
...@@ -76,21 +76,82 @@ struct discovery { ...@@ -76,21 +76,82 @@ struct discovery {
char *buf_alloc; char *buf_alloc;
char *buf; char *buf;
size_t len; size_t len;
struct ref *refs;
unsigned proto_git : 1; unsigned proto_git : 1;
}; };
static struct discovery *last_discovery; 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) static void free_discovery(struct discovery *d)
{ {
if (d) { if (d) {
if (d == last_discovery) if (d == last_discovery)
last_discovery = NULL; last_discovery = NULL;
free(d->buf_alloc); free(d->buf_alloc);
free_refs(d->refs);
free(d); 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 exp = STRBUF_INIT;
struct strbuf type = 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 && if (maybe_smart &&
(5 <= last->len && last->buf[4] == '#') && (5 <= last->len && last->buf[4] == '#') &&
!strbuf_cmp(&exp, &type)) { !strbuf_cmp(&exp, &type)) {
char *line;
/* /*
* smart HTTP response; validate that the service * smart HTTP response; validate that the service
* pkt-line matches our request. * pkt-line matches our request.
*/ */
if (packet_get_line(&buffer, &last->buf, &last->len) <= 0) line = packet_read_line_buf(&last->buf, &last->len, NULL);
die("%s has invalid packet header", refs_url);
if (buffer.len && buffer.buf[buffer.len - 1] == '\n')
strbuf_setlen(&buffer, buffer.len - 1);
strbuf_reset(&exp); strbuf_reset(&exp);
strbuf_addf(&exp, "# service=%s", service); strbuf_addf(&exp, "# service=%s", service);
if (strbuf_cmp(&exp, &buffer)) if (strcmp(line, exp.buf))
die("invalid server response; got '%s'", buffer.buf); die("invalid server response; got '%s'", line);
strbuf_release(&exp); strbuf_release(&exp);
/* The header can include additional metadata lines, up /* The header can include additional metadata lines, up
* until a packet flush marker. Ignore these now, but * until a packet flush marker. Ignore these now, but
* in the future we might start to scan them. * in the future we might start to scan them.
*/ */
strbuf_reset(&buffer); while (packet_read_line_buf(&last->buf, &last->len, NULL))
while (packet_get_line(&buffer, &last->buf, &last->len) > 0) ;
strbuf_reset(&buffer);
last->proto_git = 1; 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); free(refs_url);
strbuf_release(&exp); strbuf_release(&exp);
strbuf_release(&type); 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; 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) static struct ref *get_refs(int for_push)
{ {
struct discovery *heads; struct discovery *heads;
if (for_push) if (for_push)
heads = discover_refs("git-receive-pack"); heads = discover_refs("git-receive-pack", for_push);
else else
heads = discover_refs("git-upload-pack"); heads = discover_refs("git-upload-pack", for_push);
if (heads->proto_git) return heads->refs;
return parse_git_refs(heads, for_push);
return parse_info_refs(heads);
} }
static void output_refs(struct ref *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"); printf("\n");
fflush(stdout); fflush(stdout);
free_refs(refs);
} }
struct rpc_state { 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) { if (!avail) {
rpc->initial_buffer = 0; 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) if (!avail)
return 0; return 0;
rpc->pos = 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; break;
} }
n = packet_read_line(rpc->out, buf, left); n = packet_read(rpc->out, NULL, NULL, buf, left, 0);
if (!n) if (!n)
break; break;
rpc->len += n; 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); rpc->hdr_accept = strbuf_detach(&buf, NULL);
while (!err) { 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) if (!n)
break; break;
rpc->pos = 0; 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); err = rpc_service(&rpc, heads);
if (rpc.result.len) 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(&rpc.result);
strbuf_release(&preamble); strbuf_release(&preamble);
free(depth_arg); 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) 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) if (d->proto_git)
return fetch_git(d, nr_heads, to_fetch); return fetch_git(d, nr_heads, to_fetch);
else 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); err = rpc_service(&rpc, heads);
if (rpc.result.len) 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(&rpc.result);
free(argv); free(argv);
return err; 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) 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; int ret;
if (heads->proto_git) if (heads->proto_git)
......
...@@ -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) static int receive_status(int in, struct ref *refs)
{ {
struct ref *hint; struct ref *hint;
char line[1000];
int ret = 0; int ret = 0;
int len = packet_read_line(in, line, sizeof(line)); char *line = packet_read_line(in, NULL);
if (len < 10 || memcmp(line, "unpack ", 7)) if (prefixcmp(line, "unpack "))
return error("did not receive remote status"); return error("did not receive remote status");
if (memcmp(line, "unpack ok\n", 10)) { if (strcmp(line, "unpack ok")) {
char *p = line + strlen(line) - 1;
if (*p == '\n')
*p = '\0';
error("unpack failed: %s", line + 7); error("unpack failed: %s", line + 7);
ret = -1; 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) { while (1) {
char *refname; char *refname;
char *msg; char *msg;
len = packet_read_line(in, line, sizeof(line)); line = packet_read_line(in, NULL);
if (!len) if (!line)
break; break;
if (len < 3 || if (prefixcmp(line, "ok ") && prefixcmp(line, "ng ")) {
(memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) { error("invalid ref status from remote: %s", line);
fprintf(stderr, "protocol error: %s\n", line);
ret = -1; ret = -1;
break; break;
} }
line[strlen(line)-1] = '\0';
refname = line + 3; refname = line + 3;
msg = strchr(refname, ' '); msg = strchr(refname, ' ');
if (msg) 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); send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
} }
} else { } else {
safe_write(out, req_buf.buf, req_buf.len); write_or_die(out, req_buf.buf, req_buf.len);
packet_flush(out); packet_flush(out);
} }
strbuf_release(&req_buf); strbuf_release(&req_buf);
......
#include "cache.h"
#include "pkt-line.h" #include "pkt-line.h"
#include "sideband.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) { while (1) {
int band, len; 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) if (len == 0)
break; break;
if (len < 1) { 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); } while (len);
continue; continue;
case 1: case 1:
safe_write(out, buf + pf+1, len); write_or_die(out, buf + pf+1, len);
continue; continue;
default: default:
fprintf(stderr, "%s: protocol error: bad band #%d\n", 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) { if (0 <= band) {
sprintf(hdr, "%04x", n + 5); sprintf(hdr, "%04x", n + 5);
hdr[4] = band; hdr[4] = band;
safe_write(fd, hdr, 5); write_or_die(fd, hdr, 5);
} else { } else {
sprintf(hdr, "%04x", n + 4); 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; p += n;
sz -= n; sz -= n;
} }
......
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
#define SIDEBAND_PROTOCOL_ERROR -2 #define SIDEBAND_PROTOCOL_ERROR -2
#define SIDEBAND_REMOTE_ERROR -1 #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); 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); ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max);
......
...@@ -4,10 +4,6 @@ test_description='test automatic tag following' ...@@ -4,10 +4,6 @@ test_description='test automatic tag following'
. ./test-lib.sh . ./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: # End state of the repository:
# #
# T - tag1 S - tag2 # T - tag1 S - tag2
...@@ -17,7 +13,7 @@ fi ...@@ -17,7 +13,7 @@ fi
# \ C - origin/cat \ # \ C - origin/cat \
# origin/master master # origin/master master
test_expect_success NOT_MINGW setup ' test_expect_success setup '
test_tick && test_tick &&
echo ichi >file && echo ichi >file &&
git add 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 U=UPLOAD_LOG
UPATH="$(pwd)/$U"
test_expect_success NOT_MINGW 'setup expect' ' test_expect_success 'setup expect' '
cat - <<EOF >expect cat - <<EOF >expect
#S
want $A want $A
#E
EOF 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 && rm -f $U &&
( (
cd cloned && 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 $A = $(git rev-parse --verify origin/master)
) && ) &&
test -s $U && get_needs $U >actual &&
cut -d" " -f1,2 $U >actual &&
test_cmp expect 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 && git tag -a -m tag1 tag1 $A &&
T=$(git rev-parse --verify tag1) && 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 git checkout master
' '
test_expect_success NOT_MINGW 'setup expect' ' test_expect_success 'setup expect' '
cat - <<EOF >expect cat - <<EOF >expect
#S
want $C want $C
want $T want $T
#E
EOF 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 && rm -f $U &&
( (
cd cloned && 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 $C = $(git rev-parse --verify origin/cat) &&
test $T = $(git rev-parse --verify tag1) && test $T = $(git rev-parse --verify tag1) &&
test $A = $(git rev-parse --verify tag1^0) test $A = $(git rev-parse --verify tag1^0)
) && ) &&
test -s $U && get_needs $U >actual &&
cut -d" " -f1,2 $U >actual &&
test_cmp expect 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 && test_tick &&
echo O >file && echo O >file &&
git add 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) S=$(git rev-parse --verify tag2)
' '
test_expect_success NOT_MINGW 'setup expect' ' test_expect_success 'setup expect' '
cat - <<EOF >expect cat - <<EOF >expect
#S
want $B want $B
want $S want $S
#E
EOF 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 && rm -f $U &&
( (
cd cloned && 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 origin/master) &&
test $B = $(git rev-parse --verify tag2^0) && test $B = $(git rev-parse --verify tag2^0) &&
test $S = $(git rev-parse --verify tag2) test $S = $(git rev-parse --verify tag2)
) && ) &&
test -s $U && get_needs $U >actual &&
cut -d" " -f1,2 $U >actual &&
test_cmp expect actual test_cmp expect actual
' '
test_expect_success NOT_MINGW 'setup expect' ' test_expect_success 'setup expect' '
cat - <<EOF >expect cat - <<EOF >expect
#S
want $B want $B
want $S want $S
#E
EOF 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 git branch -D cat
rm -f $U 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 && cd clone2 &&
git init && git init &&
git remote add origin .. && 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 $B = $(git rev-parse --verify origin/master) &&
test $S = $(git rev-parse --verify tag2) && test $S = $(git rev-parse --verify tag2) &&
test $B = $(git rev-parse --verify tag2^0) && test $B = $(git rev-parse --verify tag2^0) &&
test $T = $(git rev-parse --verify tag1) && test $T = $(git rev-parse --verify tag1) &&
test $A = $(git rev-parse --verify tag1^0) test $A = $(git rev-parse --verify tag1^0)
) && ) &&
test -s $U && get_needs $U >actual &&
cut -d" " -f1,2 $U >actual &&
test_cmp expect actual test_cmp expect actual
' '
......
...@@ -54,11 +54,14 @@ cd "$base_dir" ...@@ -54,11 +54,14 @@ cd "$base_dir"
rm -f "$U.D" rm -f "$U.D"
test_expect_success 'cloning with reference (no -l -s)' \ 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"' GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D
'
test_expect_success 'fetched no objects' \ test_expect_success 'fetched no objects' '
'! grep "^want" "$U.D"' test -s "$U.D" &&
! grep " want" "$U.D"
'
cd "$base_dir" 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 && cd K &&
git remote add J "file://$base_dir/J" && 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) && 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) && 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 test_done
...@@ -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; struct ref *refs;
connect_setup(transport, for_push, 0); 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); for_push ? REF_NORMAL : 0, &data->extra_have);
data->got_remote_heads = 1; 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) { if (!data->got_remote_heads) {
connect_setup(transport, 0, 0); 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; 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; struct ref *tmp_refs;
connect_setup(transport, 1, 0); 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; data->got_remote_heads = 1;
} }
......
...@@ -44,7 +44,6 @@ static unsigned int timeout; ...@@ -44,7 +44,6 @@ static unsigned int timeout;
* otherwise maximum packet size (up to 65520 bytes). * otherwise maximum packet size (up to 65520 bytes).
*/ */
static int use_sideband; static int use_sideband;
static int debug_fd;
static int advertise_refs; static int advertise_refs;
static int stateless_rpc; static int stateless_rpc;
...@@ -53,13 +52,6 @@ static void reset_timeout(void) ...@@ -53,13 +52,6 @@ static void reset_timeout(void)
alarm(timeout); 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) static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
{ {
if (use_sideband) 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); xwrite(fd, data, sz);
return sz; return sz;
} }
return safe_write(fd, data, sz); write_or_die(fd, data, sz);
return sz;
} }
static FILE *pack_pipe = NULL; 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 int get_common_commits(void)
{ {
static char line[1000];
unsigned char sha1[20]; unsigned char sha1[20];
char last_hex[41]; char last_hex[41];
int got_common = 0; 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; save_commit_buffer = 0;
for (;;) { for (;;) {
int len = packet_read_line(0, line, sizeof(line)); char *line = packet_read_line(0, NULL);
reset_timeout(); reset_timeout();
if (!len) { if (!line) {
if (multi_ack == 2 && got_common if (multi_ack == 2 && got_common
&& !got_other && ok_to_give_up()) { && !got_other && ok_to_give_up()) {
sent_ready = 1; 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; got_other = 0;
continue; continue;
} }
strip(line, len);
if (!prefixcmp(line, "have ")) { if (!prefixcmp(line, "have ")) {
switch (got_sha1(line+5, sha1)) { switch (got_sha1(line+5, sha1)) {
case -1: /* they have what we do not */ case -1: /* they have what we do not */
...@@ -581,36 +572,33 @@ static void check_non_tip(void) ...@@ -581,36 +572,33 @@ static void check_non_tip(void)
static void receive_needs(void) static void receive_needs(void)
{ {
struct object_array shallows = OBJECT_ARRAY_INIT; struct object_array shallows = OBJECT_ARRAY_INIT;
static char line[1000]; int depth = 0;
int len, depth = 0;
int has_non_tip = 0; int has_non_tip = 0;
shallow_nr = 0; shallow_nr = 0;
if (debug_fd)
write_str_in_full(debug_fd, "#S\n");
for (;;) { for (;;) {
struct object *o; struct object *o;
const char *features; const char *features;
unsigned char sha1_buf[20]; unsigned char sha1_buf[20];
len = packet_read_line(0, line, sizeof(line)); char *line = packet_read_line(0, NULL);
reset_timeout(); reset_timeout();
if (!len) if (!line)
break; break;
if (debug_fd)
write_in_full(debug_fd, line, len);
if (!prefixcmp(line, "shallow ")) { if (!prefixcmp(line, "shallow ")) {
unsigned char sha1[20]; unsigned char sha1[20];
struct object *object; struct object *object;
if (get_sha1(line + 8, sha1)) if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line); die("invalid shallow line: %s", line);
object = parse_object(sha1); object = parse_object(sha1);
if (!object) if (!object)
die("did not find object for %s", line); die("did not find object for %s", line);
if (object->type != OBJ_COMMIT) if (object->type != OBJ_COMMIT)
die("invalid shallow object %s", sha1_to_hex(sha1)); die("invalid shallow object %s", sha1_to_hex(sha1));
object->flags |= CLIENT_SHALLOW; if (!(object->flags & CLIENT_SHALLOW)) {
add_object_array(object, NULL, &shallows); object->flags |= CLIENT_SHALLOW;
add_object_array(object, NULL, &shallows);
}
continue; continue;
} }
if (!prefixcmp(line, "deepen ")) { 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); 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 * 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()) if (is_repository_shallow())
die("attempt to fetch/clone from a shallow repository"); die("attempt to fetch/clone from a shallow repository");
git_config(upload_pack_config, NULL); git_config(upload_pack_config, NULL);
if (getenv("GIT_DEBUG_SEND_PACK"))
debug_fd = atoi(getenv("GIT_DEBUG_SEND_PACK"));
upload_pack(); upload_pack();
return 0; return 0;
} }
#include "cache.h" #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 * Some cases use stdio, but want to flush after the write
* to get error handling (and to get better interactive * 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; return;
} }
if (fflush(f)) { if (fflush(f)) {
if (errno == EPIPE) check_pipe(errno);
exit(0);
die_errno("write failure on '%s'", desc); 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) void write_or_die(int fd, const void *buf, size_t count)
{ {
if (write_in_full(fd, buf, count) < 0) { if (write_in_full(fd, buf, count) < 0) {
if (errno == EPIPE) check_pipe(errno);
exit(0);
die_errno("write error"); 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) 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 (write_in_full(fd, buf, count) < 0) {
if (errno == EPIPE) check_pipe(errno);
exit(0);
fprintf(stderr, "%s: write error (%s)\n", fprintf(stderr, "%s: write error (%s)\n",
msg, strerror(errno)); msg, strerror(errno));
return 0; return 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册