Imported Upstream version 2.18.4
[platform/upstream/git.git] / pkt-line.c
index bc63b3b..a593c08 100644 (file)
@@ -1,49 +1,83 @@
 #include "cache.h"
 #include "pkt-line.h"
+#include "run-command.h"
 
 char packet_buffer[LARGE_PACKET_MAX];
 static const char *packet_trace_prefix = "git";
-static const char trace_key[] = "GIT_TRACE_PACKET";
+static struct trace_key trace_packet = TRACE_KEY_INIT(PACKET);
+static struct trace_key trace_pack = TRACE_KEY_INIT(PACKFILE);
 
 void packet_trace_identity(const char *prog)
 {
        packet_trace_prefix = xstrdup(prog);
 }
 
+static const char *get_trace_prefix(void)
+{
+       return in_async() ? "sideband" : packet_trace_prefix;
+}
+
+static int packet_trace_pack(const char *buf, unsigned int len, int sideband)
+{
+       if (!sideband) {
+               trace_verbatim(&trace_pack, buf, len);
+               return 1;
+       } else if (len && *buf == '\1') {
+               trace_verbatim(&trace_pack, buf + 1, len - 1);
+               return 1;
+       } else {
+               /* it's another non-pack sideband */
+               return 0;
+       }
+}
+
 static void packet_trace(const char *buf, unsigned int len, int write)
 {
        int i;
        struct strbuf out;
+       static int in_pack, sideband;
+
+       if (!trace_want(&trace_packet) && !trace_want(&trace_pack))
+               return;
+
+       if (in_pack) {
+               if (packet_trace_pack(buf, len, sideband))
+                       return;
+       } else if (starts_with(buf, "PACK") || starts_with(buf, "\1PACK")) {
+               in_pack = 1;
+               sideband = *buf == '\1';
+               packet_trace_pack(buf, len, sideband);
 
-       if (!trace_want(trace_key))
+               /*
+                * Make a note in the human-readable trace that the pack data
+                * started.
+                */
+               buf = "PACK ...";
+               len = strlen(buf);
+       }
+
+       if (!trace_want(&trace_packet))
                return;
 
        /* +32 is just a guess for header + quoting */
        strbuf_init(&out, len+32);
 
        strbuf_addf(&out, "packet: %12s%c ",
-                   packet_trace_prefix, write ? '>' : '<');
+                   get_trace_prefix(), write ? '>' : '<');
 
-       if ((len >= 4 && starts_with(buf, "PACK")) ||
-           (len >= 5 && starts_with(buf+1, "PACK"))) {
-               strbuf_addstr(&out, "PACK ...");
-               unsetenv(trace_key);
-       }
-       else {
-               /* XXX we should really handle printable utf8 */
-               for (i = 0; i < len; i++) {
-                       /* suppress newlines */
-                       if (buf[i] == '\n')
-                               continue;
-                       if (buf[i] >= 0x20 && buf[i] <= 0x7e)
-                               strbuf_addch(&out, buf[i]);
-                       else
-                               strbuf_addf(&out, "\\%o", buf[i]);
-               }
+       /* XXX we should really handle printable utf8 */
+       for (i = 0; i < len; i++) {
+               /* suppress newlines */
+               if (buf[i] == '\n')
+                       continue;
+               if (buf[i] >= 0x20 && buf[i] <= 0x7e)
+                       strbuf_addch(&out, buf[i]);
+               else
+                       strbuf_addf(&out, "\\%o", buf[i]);
        }
 
        strbuf_addch(&out, '\n');
-       trace_strbuf(trace_key, &out);
+       trace_strbuf(&trace_packet, &out);
        strbuf_release(&out);
 }
 
@@ -57,51 +91,184 @@ void packet_flush(int fd)
        write_or_die(fd, "0000", 4);
 }
 
+void packet_delim(int fd)
+{
+       packet_trace("0001", 4, 1);
+       write_or_die(fd, "0001", 4);
+}
+
+int packet_flush_gently(int fd)
+{
+       packet_trace("0000", 4, 1);
+       if (write_in_full(fd, "0000", 4) < 0)
+               return error("flush packet write failed");
+       return 0;
+}
+
 void packet_buf_flush(struct strbuf *buf)
 {
        packet_trace("0000", 4, 1);
        strbuf_add(buf, "0000", 4);
 }
 
-#define hex(a) (hexchar[(a) & 15])
-static char buffer[1000];
-static unsigned format_packet(const char *fmt, va_list args)
+void packet_buf_delim(struct strbuf *buf)
+{
+       packet_trace("0001", 4, 1);
+       strbuf_add(buf, "0001", 4);
+}
+
+static void set_packet_header(char *buf, const int size)
 {
        static char hexchar[] = "0123456789abcdef";
-       unsigned n;
 
-       n = vsnprintf(buffer + 4, sizeof(buffer) - 4, fmt, args);
-       if (n >= sizeof(buffer)-4)
+       #define hex(a) (hexchar[(a) & 15])
+       buf[0] = hex(size >> 12);
+       buf[1] = hex(size >> 8);
+       buf[2] = hex(size >> 4);
+       buf[3] = hex(size);
+       #undef hex
+}
+
+static void format_packet(struct strbuf *out, const char *fmt, va_list args)
+{
+       size_t orig_len, n;
+
+       orig_len = out->len;
+       strbuf_addstr(out, "0000");
+       strbuf_vaddf(out, fmt, args);
+       n = out->len - orig_len;
+
+       if (n > LARGE_PACKET_MAX)
                die("protocol error: impossibly long line");
-       n += 4;
-       buffer[0] = hex(n >> 12);
-       buffer[1] = hex(n >> 8);
-       buffer[2] = hex(n >> 4);
-       buffer[3] = hex(n);
-       packet_trace(buffer+4, n-4, 1);
-       return n;
+
+       set_packet_header(&out->buf[orig_len], n);
+       packet_trace(out->buf + orig_len + 4, n - 4, 1);
+}
+
+static int packet_write_fmt_1(int fd, int gently,
+                             const char *fmt, va_list args)
+{
+       static struct strbuf buf = STRBUF_INIT;
+
+       strbuf_reset(&buf);
+       format_packet(&buf, fmt, args);
+       if (write_in_full(fd, buf.buf, buf.len) < 0) {
+               if (!gently) {
+                       check_pipe(errno);
+                       die_errno("packet write with format failed");
+               }
+               return error("packet write with format failed");
+       }
+
+       return 0;
 }
 
-void packet_write(int fd, const char *fmt, ...)
+void packet_write_fmt(int fd, const char *fmt, ...)
 {
        va_list args;
-       unsigned n;
 
        va_start(args, fmt);
-       n = format_packet(fmt, args);
+       packet_write_fmt_1(fd, 0, fmt, args);
        va_end(args);
-       write_or_die(fd, buffer, n);
+}
+
+int packet_write_fmt_gently(int fd, const char *fmt, ...)
+{
+       int status;
+       va_list args;
+
+       va_start(args, fmt);
+       status = packet_write_fmt_1(fd, 1, fmt, args);
+       va_end(args);
+       return status;
+}
+
+static int packet_write_gently(const int fd_out, const char *buf, size_t size)
+{
+       static char packet_write_buffer[LARGE_PACKET_MAX];
+       size_t packet_size;
+
+       if (size > sizeof(packet_write_buffer) - 4)
+               return error("packet write failed - data exceeds max packet size");
+
+       packet_trace(buf, size, 1);
+       packet_size = size + 4;
+       set_packet_header(packet_write_buffer, packet_size);
+       memcpy(packet_write_buffer + 4, buf, size);
+       if (write_in_full(fd_out, packet_write_buffer, packet_size) < 0)
+               return error("packet write failed");
+       return 0;
+}
+
+void packet_write(int fd_out, const char *buf, size_t size)
+{
+       if (packet_write_gently(fd_out, buf, size))
+               die_errno("packet write failed");
 }
 
 void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
 {
        va_list args;
-       unsigned n;
 
        va_start(args, fmt);
-       n = format_packet(fmt, args);
+       format_packet(buf, fmt, args);
        va_end(args);
-       strbuf_add(buf, buffer, n);
+}
+
+void packet_buf_write_len(struct strbuf *buf, const char *data, size_t len)
+{
+       size_t orig_len, n;
+
+       orig_len = buf->len;
+       strbuf_addstr(buf, "0000");
+       strbuf_add(buf, data, len);
+       n = buf->len - orig_len;
+
+       if (n > LARGE_PACKET_MAX)
+               die("protocol error: impossibly long line");
+
+       set_packet_header(&buf->buf[orig_len], n);
+       packet_trace(data, len, 1);
+}
+
+int write_packetized_from_fd(int fd_in, int fd_out)
+{
+       static char buf[LARGE_PACKET_DATA_MAX];
+       int err = 0;
+       ssize_t bytes_to_write;
+
+       while (!err) {
+               bytes_to_write = xread(fd_in, buf, sizeof(buf));
+               if (bytes_to_write < 0)
+                       return COPY_READ_ERROR;
+               if (bytes_to_write == 0)
+                       break;
+               err = packet_write_gently(fd_out, buf, bytes_to_write);
+       }
+       if (!err)
+               err = packet_flush_gently(fd_out);
+       return err;
+}
+
+int write_packetized_from_buf(const char *src_in, size_t len, int fd_out)
+{
+       int err = 0;
+       size_t bytes_written = 0;
+       size_t bytes_to_write;
+
+       while (!err) {
+               if ((len - bytes_written) > LARGE_PACKET_DATA_MAX)
+                       bytes_to_write = LARGE_PACKET_DATA_MAX;
+               else
+                       bytes_to_write = len - bytes_written;
+               if (bytes_to_write == 0)
+                       break;
+               err = packet_write_gently(fd_out, src_in + bytes_written, bytes_to_write);
+               bytes_written += bytes_to_write;
+       }
+       if (!err)
+               err = packet_flush_gently(fd_out);
+       return err;
 }
 
 static int get_packet_data(int fd, char **src_buf, size_t *src_size,
@@ -110,7 +277,7 @@ static int get_packet_data(int fd, char **src_buf, size_t *src_size,
        ssize_t ret;
 
        if (fd >= 0 && src_buf && *src_buf)
-               die("BUG: multiple sources given to packet_read");
+               BUG("multiple sources given to packet_read");
 
        /* Read up to "size" bytes from our source, whatever it is. */
        if (src_buf && *src_buf) {
@@ -125,7 +292,7 @@ static int get_packet_data(int fd, char **src_buf, size_t *src_size,
        }
 
        /* And complain if we didn't get enough bytes to satisfy the read. */
-       if (ret < size) {
+       if (ret != size) {
                if (options & PACKET_READ_GENTLE_ON_EOF)
                        return -1;
 
@@ -137,51 +304,47 @@ static int get_packet_data(int fd, char **src_buf, size_t *src_size,
 
 static int packet_length(const char *linelen)
 {
-       int n;
-       int len = 0;
-
-       for (n = 0; n < 4; n++) {
-               unsigned char c = linelen[n];
-               len <<= 4;
-               if (c >= '0' && c <= '9') {
-                       len += c - '0';
-                       continue;
-               }
-               if (c >= 'a' && c <= 'f') {
-                       len += c - 'a' + 10;
-                       continue;
-               }
-               if (c >= 'A' && c <= 'F') {
-                       len += c - 'A' + 10;
-                       continue;
-               }
-               return -1;
-       }
-       return len;
+       int val = hex2chr(linelen);
+       return (val < 0) ? val : (val << 8) | hex2chr(linelen + 2);
 }
 
-int packet_read(int fd, char **src_buf, size_t *src_len,
-               char *buffer, unsigned size, int options)
+enum packet_read_status packet_read_with_status(int fd, char **src_buffer,
+                                               size_t *src_len, char *buffer,
+                                               unsigned size, int *pktlen,
+                                               int options)
 {
-       int len, ret;
+       int len;
        char linelen[4];
 
-       ret = get_packet_data(fd, src_buf, src_len, linelen, 4, options);
-       if (ret < 0)
-               return ret;
+       if (get_packet_data(fd, src_buffer, src_len, linelen, 4, options) < 0) {
+               *pktlen = -1;
+               return PACKET_READ_EOF;
+       }
+
        len = packet_length(linelen);
-       if (len < 0)
+
+       if (len < 0) {
                die("protocol error: bad line length character: %.4s", linelen);
-       if (!len) {
+       } else if (!len) {
                packet_trace("0000", 4, 0);
-               return 0;
+               *pktlen = 0;
+               return PACKET_READ_FLUSH;
+       } else if (len == 1) {
+               packet_trace("0001", 4, 0);
+               *pktlen = 0;
+               return PACKET_READ_DELIM;
+       } else if (len < 4) {
+               die("protocol error: bad line length %d", len);
        }
+
        len -= 4;
-       if (len >= size)
+       if ((unsigned)len >= size)
                die("protocol error: bad line length %d", len);
-       ret = get_packet_data(fd, src_buf, src_len, buffer, len, options);
-       if (ret < 0)
-               return ret;
+
+       if (get_packet_data(fd, src_buffer, src_len, buffer, len, options) < 0) {
+               *pktlen = -1;
+               return PACKET_READ_EOF;
+       }
 
        if ((options & PACKET_READ_CHOMP_NEWLINE) &&
            len && buffer[len-1] == '\n')
@@ -189,7 +352,19 @@ int packet_read(int fd, char **src_buf, size_t *src_len,
 
        buffer[len] = 0;
        packet_trace(buffer, len, 0);
-       return len;
+       *pktlen = len;
+       return PACKET_READ_NORMAL;
+}
+
+int packet_read(int fd, char **src_buffer, size_t *src_len,
+               char *buffer, unsigned size, int options)
+{
+       int pktlen = -1;
+
+       packet_read_with_status(fd, src_buffer, src_len, buffer, size,
+                               &pktlen, options);
+
+       return pktlen;
 }
 
 static char *packet_read_line_generic(int fd,
@@ -201,7 +376,7 @@ static char *packet_read_line_generic(int fd,
                              PACKET_READ_CHOMP_NEWLINE);
        if (dst_len)
                *dst_len = len;
-       return len ? packet_buffer : NULL;
+       return (len > 0) ? packet_buffer : NULL;
 }
 
 char *packet_read_line(int fd, int *len_p)
@@ -209,7 +384,101 @@ char *packet_read_line(int fd, int *len_p)
        return packet_read_line_generic(fd, NULL, NULL, len_p);
 }
 
+int packet_read_line_gently(int fd, int *dst_len, char **dst_line)
+{
+       int len = packet_read(fd, NULL, NULL,
+                             packet_buffer, sizeof(packet_buffer),
+                             PACKET_READ_CHOMP_NEWLINE|PACKET_READ_GENTLE_ON_EOF);
+       if (dst_len)
+               *dst_len = len;
+       if (dst_line)
+               *dst_line = (len > 0) ? packet_buffer : NULL;
+       return len;
+}
+
 char *packet_read_line_buf(char **src, size_t *src_len, int *dst_len)
 {
        return packet_read_line_generic(-1, src, src_len, dst_len);
 }
+
+ssize_t read_packetized_to_strbuf(int fd_in, struct strbuf *sb_out)
+{
+       int packet_len;
+
+       size_t orig_len = sb_out->len;
+       size_t orig_alloc = sb_out->alloc;
+
+       for (;;) {
+               strbuf_grow(sb_out, LARGE_PACKET_DATA_MAX);
+               packet_len = packet_read(fd_in, NULL, NULL,
+                       /* strbuf_grow() above always allocates one extra byte to
+                        * store a '\0' at the end of the string. packet_read()
+                        * writes a '\0' extra byte at the end, too. Let it know
+                        * that there is already room for the extra byte.
+                        */
+                       sb_out->buf + sb_out->len, LARGE_PACKET_DATA_MAX+1,
+                       PACKET_READ_GENTLE_ON_EOF);
+               if (packet_len <= 0)
+                       break;
+               sb_out->len += packet_len;
+       }
+
+       if (packet_len < 0) {
+               if (orig_alloc == 0)
+                       strbuf_release(sb_out);
+               else
+                       strbuf_setlen(sb_out, orig_len);
+               return packet_len;
+       }
+       return sb_out->len - orig_len;
+}
+
+/* Packet Reader Functions */
+void packet_reader_init(struct packet_reader *reader, int fd,
+                       char *src_buffer, size_t src_len,
+                       int options)
+{
+       memset(reader, 0, sizeof(*reader));
+
+       reader->fd = fd;
+       reader->src_buffer = src_buffer;
+       reader->src_len = src_len;
+       reader->buffer = packet_buffer;
+       reader->buffer_size = sizeof(packet_buffer);
+       reader->options = options;
+}
+
+enum packet_read_status packet_reader_read(struct packet_reader *reader)
+{
+       if (reader->line_peeked) {
+               reader->line_peeked = 0;
+               return reader->status;
+       }
+
+       reader->status = packet_read_with_status(reader->fd,
+                                                &reader->src_buffer,
+                                                &reader->src_len,
+                                                reader->buffer,
+                                                reader->buffer_size,
+                                                &reader->pktlen,
+                                                reader->options);
+
+       if (reader->status == PACKET_READ_NORMAL)
+               reader->line = reader->buffer;
+       else
+               reader->line = NULL;
+
+       return reader->status;
+}
+
+enum packet_read_status packet_reader_peek(struct packet_reader *reader)
+{
+       /* Only allow peeking a single line */
+       if (reader->line_peeked)
+               return reader->status;
+
+       /* Peek a line by reading it and setting peeked flag */
+       packet_reader_read(reader);
+       reader->line_peeked = 1;
+       return reader->status;
+}