From a250f73783c06d7789ac65a395d9247f4ab44c26 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Wed, 12 Aug 2015 22:57:58 +0200 Subject: [PATCH] common/iobuf.c: Improve iobuf_peek. * common/iobuf.c (underflow): Take additional parameter clear_pending_eof. If not set, don't clear a pending eof when returning EOF. Update callers. (iobuf_peek): Fill the internal buffer, if needed, to be able to better satisfy any request. -- Signed-off-by: Neal H. Walfield . --- common/iobuf.c | 50 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/common/iobuf.c b/common/iobuf.c index fed98397a..4f098859d 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -161,7 +161,7 @@ block_filter_ctx_t; static int special_names_enabled; /* Local prototypes. */ -static int underflow (iobuf_t a); +static int underflow (iobuf_t a, int clear_pending_eof); static int translate_file_handle (int fd, int for_write); @@ -1762,7 +1762,7 @@ pop_filter (iobuf_t a, int (*f) (void *opaque, int control, * the first byte or -1 on EOF. */ static int -underflow (iobuf_t a) +underflow (iobuf_t a, int clear_pending_eof) { size_t len; int rc; @@ -1792,6 +1792,9 @@ underflow (iobuf_t a) if (DBG_IOBUF) log_debug ("iobuf-%d.%d: underflow: eof (pending eof)\n", a->no, a->subno); + if (! clear_pending_eof) + return -1; + if (a->chain) /* A filter follows this one. Free this filter. */ { @@ -1865,7 +1868,7 @@ underflow (iobuf_t a) a->filter = NULL; a->filter_eof = 1; - if (a->d.len == 0 && a->chain) + if (clear_pending_eof && a->d.len == 0 && a->chain) /* We don't need to keep this filter around at all: - we got an EOF @@ -1967,7 +1970,7 @@ iobuf_readbyte (iobuf_t a) { c = a->d.buf[a->d.start++]; } - else if ((c = underflow (a)) == -1) + else if ((c = underflow (a, 1)) == -1) return -1; /* EOF */ a->nbytes++; @@ -2017,7 +2020,7 @@ iobuf_read (iobuf_t a, void *buffer, unsigned int buflen) } if (n < buflen) { - if ((c = underflow (a)) == -1) + if ((c = underflow (a, 1)) == -1) { a->nbytes += n; return n ? n : -1 /*EOF*/; @@ -2034,29 +2037,42 @@ iobuf_read (iobuf_t a, void *buffer, unsigned int buflen) -/**************** - * Have a look at the iobuf. - * NOTE: This only works in special cases. - */ int iobuf_peek (iobuf_t a, byte * buf, unsigned buflen) { int n = 0; - if (a->filter_eof) - return -1; + assert (buflen > 0); + assert (a->use == IOBUF_INPUT); - if (!(a->d.start < a->d.len)) + if (buflen > a->d.size) + /* We can't peek more than we can buffer. */ + buflen = a->d.size; + + /* Try to fill the internal buffer with enough data to satisfy the + request. */ + while (buflen > a->d.len - a->d.start) { - if (underflow (a) == -1) - return -1; - /* And unget this character. */ + if (underflow (a, 0) == -1) + /* EOF. We can't read any more. */ + break; + + /* Underflow consumes the first character (it's the return + value). unget() it by resetting the "file position". */ assert (a->d.start == 1); a->d.start = 0; } - for (n = 0; n < buflen && (a->d.start + n) < a->d.len; n++, buf++) - *buf = a->d.buf[n]; + n = a->d.len - a->d.start; + if (n > buflen) + n = buflen; + + if (n == 0) + /* EOF. */ + return -1; + + memcpy (buf, &a->d.buf[a->d.start], n); + return n; }