Create a functions that can read malformed messages without dying.
Includes creation of flag PACKET_READ_GENTLE_ALL. For use handling
prime-clone (or other server error) responses.

Signed-off-by: Kevin Wern <kevin.m.w...@gmail.com>
---
 pkt-line.c | 47 ++++++++++++++++++++++++++++++++++++++---------
 pkt-line.h | 16 ++++++++++++++++
 2 files changed, 54 insertions(+), 9 deletions(-)

diff --git a/pkt-line.c b/pkt-line.c
index 62fdb37..96060e5 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -155,13 +155,17 @@ static int get_packet_data(int fd, char **src_buf, size_t 
*src_size,
                *src_size -= ret;
        } else {
                ret = read_in_full(fd, dst, size);
-               if (ret < 0)
+               if (ret < 0) {
+                       if (options & PACKET_READ_GENTLE_ALL)
+                               return -1;
+
                        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)
+               if (options & (PACKET_READ_GENTLE_ON_EOF | 
PACKET_READ_GENTLE_ALL))
                        return -1;
 
                die("The remote end hung up unexpectedly");
@@ -205,15 +209,23 @@ int packet_read(int fd, char **src_buf, size_t *src_len,
        if (ret < 0)
                return ret;
        len = packet_length(linelen);
-       if (len < 0)
+       if (len < 0) {
+               if (options & PACKET_READ_GENTLE_ALL)
+                       return -1;
+
                die("protocol error: bad line length character: %.4s", linelen);
+       }
        if (!len) {
                packet_trace("0000", 4, 0);
                return 0;
        }
        len -= 4;
-       if (len >= size)
+       if (len >= size) {
+               if (options & PACKET_READ_GENTLE_ALL)
+                       return -1;
+
                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;
@@ -229,22 +241,39 @@ int packet_read(int fd, char **src_buf, size_t *src_len,
 
 static char *packet_read_line_generic(int fd,
                                      char **src, size_t *src_len,
-                                     int *dst_len)
+                                     int *dst_len, int flags)
 {
        int len = packet_read(fd, src, src_len,
                              packet_buffer, sizeof(packet_buffer),
-                             PACKET_READ_CHOMP_NEWLINE);
+                             flags);
        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)
 {
-       return packet_read_line_generic(fd, NULL, NULL, len_p);
+       return packet_read_line_generic(fd, NULL, NULL, len_p,
+                       PACKET_READ_CHOMP_NEWLINE);
 }
 
 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);
+       return packet_read_line_generic(-1, src, src_len, dst_len,
+                       PACKET_READ_CHOMP_NEWLINE);
+}
+
+char *packet_read_line_gentle(int fd, int *len_p)
+{
+       return packet_read_line_generic(fd, NULL, NULL, len_p,
+                       PACKET_READ_CHOMP_NEWLINE |
+                       PACKET_READ_GENTLE_ALL);
+}
+
+
+char *packet_read_line_buf_gentle(char **src, size_t *src_len, int *dst_len)
+{
+       return packet_read_line_generic(-1, src, src_len, dst_len,
+                       PACKET_READ_CHOMP_NEWLINE |
+                       PACKET_READ_GENTLE_ALL);
 }
diff --git a/pkt-line.h b/pkt-line.h
index 3cb9d91..553e42e 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -52,11 +52,15 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, 
...) __attribute__((f
  * condition 4 (truncated input), but instead return -1. However, we will still
  * die for the other 3 conditions.
  *
+ * If options contains PACKET_READ_GENTLE_ALL, we will not die on any of the
+ * conditions, but return -1 instead.
+ *
  * 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)
+#define PACKET_READ_GENTLE_ALL    (1u<<2)
 int packet_read(int fd, char **src_buffer, size_t *src_len, char
                *buffer, unsigned size, int options);
 
@@ -75,6 +79,18 @@ char *packet_read_line(int fd, int *size);
  */
 char *packet_read_line_buf(char **src_buf, size_t *src_len, int *size);
 
+/*
+ * Same as packet_read_line, but does not die on any errors (uses
+ * PACKET_READ_GENTLE_ALL).
+ */
+char *packet_read_line_gentle(int fd, int *len_p);
+
+/*
+ * Same as packet_read_line_buf, but does not die on any errors (uses
+ * PACKET_READ_GENTLE_ALL).
+ */
+char *packet_read_line_buf_gentle(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];
-- 
2.7.4

Reply via email to