pkt-line.con commit gitweb: Add a feature to show side-by-side diff (6ba1eb5)
   1#include "cache.h"
   2#include "pkt-line.h"
   3
   4static const char *packet_trace_prefix = "git";
   5static const char trace_key[] = "GIT_TRACE_PACKET";
   6
   7void packet_trace_identity(const char *prog)
   8{
   9        packet_trace_prefix = xstrdup(prog);
  10}
  11
  12static void packet_trace(const char *buf, unsigned int len, int write)
  13{
  14        int i;
  15        struct strbuf out;
  16
  17        if (!trace_want(trace_key))
  18                return;
  19
  20        /* +32 is just a guess for header + quoting */
  21        strbuf_init(&out, len+32);
  22
  23        strbuf_addf(&out, "packet: %12s%c ",
  24                    packet_trace_prefix, write ? '>' : '<');
  25
  26        if ((len >= 4 && !prefixcmp(buf, "PACK")) ||
  27            (len >= 5 && !prefixcmp(buf+1, "PACK"))) {
  28                strbuf_addstr(&out, "PACK ...");
  29                unsetenv(trace_key);
  30        }
  31        else {
  32                /* XXX we should really handle printable utf8 */
  33                for (i = 0; i < len; i++) {
  34                        /* suppress newlines */
  35                        if (buf[i] == '\n')
  36                                continue;
  37                        if (buf[i] >= 0x20 && buf[i] <= 0x7e)
  38                                strbuf_addch(&out, buf[i]);
  39                        else
  40                                strbuf_addf(&out, "\\%o", buf[i]);
  41                }
  42        }
  43
  44        strbuf_addch(&out, '\n');
  45        trace_strbuf(trace_key, &out);
  46        strbuf_release(&out);
  47}
  48
  49/*
  50 * Write a packetized stream, where each line is preceded by
  51 * its length (including the header) as a 4-byte hex number.
  52 * A length of 'zero' means end of stream (and a length of 1-3
  53 * would be an error).
  54 *
  55 * This is all pretty stupid, but we use this packetized line
  56 * format to make a streaming format possible without ever
  57 * over-running the read buffers. That way we'll never read
  58 * into what might be the pack data (which should go to another
  59 * process entirely).
  60 *
  61 * The writing side could use stdio, but since the reading
  62 * side can't, we stay with pure read/write interfaces.
  63 */
  64ssize_t safe_write(int fd, const void *buf, ssize_t n)
  65{
  66        ssize_t nn = n;
  67        while (n) {
  68                int ret = xwrite(fd, buf, n);
  69                if (ret > 0) {
  70                        buf = (char *) buf + ret;
  71                        n -= ret;
  72                        continue;
  73                }
  74                if (!ret)
  75                        die("write error (disk full?)");
  76                die_errno("write error");
  77        }
  78        return nn;
  79}
  80
  81/*
  82 * If we buffered things up above (we don't, but we should),
  83 * we'd flush it here
  84 */
  85void packet_flush(int fd)
  86{
  87        packet_trace("0000", 4, 1);
  88        safe_write(fd, "0000", 4);
  89}
  90
  91void packet_buf_flush(struct strbuf *buf)
  92{
  93        packet_trace("0000", 4, 1);
  94        strbuf_add(buf, "0000", 4);
  95}
  96
  97#define hex(a) (hexchar[(a) & 15])
  98static char buffer[1000];
  99static unsigned format_packet(const char *fmt, va_list args)
 100{
 101        static char hexchar[] = "0123456789abcdef";
 102        unsigned n;
 103
 104        n = vsnprintf(buffer + 4, sizeof(buffer) - 4, fmt, args);
 105        if (n >= sizeof(buffer)-4)
 106                die("protocol error: impossibly long line");
 107        n += 4;
 108        buffer[0] = hex(n >> 12);
 109        buffer[1] = hex(n >> 8);
 110        buffer[2] = hex(n >> 4);
 111        buffer[3] = hex(n);
 112        packet_trace(buffer+4, n-4, 1);
 113        return n;
 114}
 115
 116void packet_write(int fd, const char *fmt, ...)
 117{
 118        va_list args;
 119        unsigned n;
 120
 121        va_start(args, fmt);
 122        n = format_packet(fmt, args);
 123        va_end(args);
 124        safe_write(fd, buffer, n);
 125}
 126
 127void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
 128{
 129        va_list args;
 130        unsigned n;
 131
 132        va_start(args, fmt);
 133        n = format_packet(fmt, args);
 134        va_end(args);
 135        strbuf_add(buf, buffer, n);
 136}
 137
 138static void safe_read(int fd, void *buffer, unsigned size)
 139{
 140        ssize_t ret = read_in_full(fd, buffer, size);
 141        if (ret < 0)
 142                die_errno("read error");
 143        else if (ret < size)
 144                die("The remote end hung up unexpectedly");
 145}
 146
 147static int packet_length(const char *linelen)
 148{
 149        int n;
 150        int len = 0;
 151
 152        for (n = 0; n < 4; n++) {
 153                unsigned char c = linelen[n];
 154                len <<= 4;
 155                if (c >= '0' && c <= '9') {
 156                        len += c - '0';
 157                        continue;
 158                }
 159                if (c >= 'a' && c <= 'f') {
 160                        len += c - 'a' + 10;
 161                        continue;
 162                }
 163                if (c >= 'A' && c <= 'F') {
 164                        len += c - 'A' + 10;
 165                        continue;
 166                }
 167                return -1;
 168        }
 169        return len;
 170}
 171
 172int packet_read_line(int fd, char *buffer, unsigned size)
 173{
 174        int len;
 175        char linelen[4];
 176
 177        safe_read(fd, linelen, 4);
 178        len = packet_length(linelen);
 179        if (len < 0)
 180                die("protocol error: bad line length character: %.4s", linelen);
 181        if (!len) {
 182                packet_trace("0000", 4, 0);
 183                return 0;
 184        }
 185        len -= 4;
 186        if (len >= size)
 187                die("protocol error: bad line length %d", len);
 188        safe_read(fd, buffer, len);
 189        buffer[len] = 0;
 190        packet_trace(buffer, len, 0);
 191        return len;
 192}
 193
 194int packet_get_line(struct strbuf *out,
 195        char **src_buf, size_t *src_len)
 196{
 197        int len;
 198
 199        if (*src_len < 4)
 200                return -1;
 201        len = packet_length(*src_buf);
 202        if (len < 0)
 203                return -1;
 204        if (!len) {
 205                *src_buf += 4;
 206                *src_len -= 4;
 207                packet_trace("0000", 4, 0);
 208                return 0;
 209        }
 210        if (*src_len < len)
 211                return -2;
 212
 213        *src_buf += 4;
 214        *src_len -= 4;
 215        len -= 4;
 216
 217        strbuf_add(out, *src_buf, len);
 218        *src_buf += len;
 219        *src_len -= len;
 220        packet_trace(out->buf, out->len, 0);
 221        return len;
 222}