From c7ad36eb0d7f872fc15e793aa1d0b6b89bc471d6 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Wed, 12 Aug 2015 22:10:37 +0200 Subject: [PATCH] common/iobuf.c: When requested, fill the buffer even if it is not empty. * common/iobuf.c (underflow): Don't require that the buffer be empty. When called, fill any available space. -- Signed-off-by: Neal H. Walfield . --- common/iobuf.c | 138 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 46 deletions(-) diff --git a/common/iobuf.c b/common/iobuf.c index 664db393f..fed98397a 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -1767,18 +1767,38 @@ underflow (iobuf_t a) size_t len; int rc; - assert (a->d.start == a->d.len); - if (a->use == IOBUF_TEMP) - return -1; /* EOF because a temp buffer can't do an underflow */ + if (DBG_IOBUF) + log_debug ("iobuf-%d.%d: underflow: buffer size: %d; still buffered: %d => space for %d bytes\n", + a->no, a->subno, + (int) a->d.size, (int) (a->d.len - a->d.start), + (int) (a->d.size - (a->d.len - a->d.start))); - if (a->filter_eof) + assert (a->use == IOBUF_INPUT); + + /* If there is still some buffered data, then move it to the start + of the buffer and try to fill the end of the buffer. (This is + useful if we are called from iobuf_peek().) */ + assert (a->d.start <= a->d.len); + a->d.len -= a->d.start; + memmove (a->d.buf, &a->d.buf[a->d.start], a->d.len); + a->d.start = 0; + + if (a->d.len == 0 && a->filter_eof) + /* The last time we tried to read from this filter, we got an EOF. + We couldn't return the EOF, because there was buffered data. + Since there is no longer any buffered data, return the + error. */ { + if (DBG_IOBUF) + log_debug ("iobuf-%d.%d: underflow: eof (pending eof)\n", + a->no, a->subno); if (a->chain) + /* A filter follows this one. Free this filter. */ { iobuf_t b = a->chain; if (DBG_IOBUF) - log_debug ("iobuf-%d.%d: pop '%s' in underflow\n", - a->no, a->subno, iobuf_desc (a)); + log_debug ("iobuf-%d.%d: filter popped (pending EOF returned)\n", + a->no, a->subno); xfree (a->d.buf); xfree (a->real_fname); memcpy (a, b, sizeof *a); @@ -1787,82 +1807,108 @@ underflow (iobuf_t a) } else a->filter_eof = 0; /* for the top level filter */ - if (DBG_IOBUF) - log_debug ("iobuf-%d.%d: underflow: eof (due to filter eof)\n", - a->no, a->subno); return -1; /* return one(!) EOF */ } - if (a->error) + + if (a->d.len == 0 && a->error) + /* The last time we tried to read from this filter, we got an + error. We couldn't return the error, because there was + buffered data. Since there is no longer any buffered data, + return the error. */ { if (DBG_IOBUF) - log_debug ("iobuf-%d.%d: error\n", a->no, a->subno); + log_debug ("iobuf-%d.%d: pending error (%s) returned\n", + a->no, a->subno, gpg_strerror (a->error)); return -1; } - if (a->filter) + if (a->filter && ! a->filter_eof && ! a->error) + /* We have a filter function and the last time we tried to read we + didn't get an EOF or an error. Try to fill the buffer. */ { - len = a->d.size; + /* Be careful to account for any buffered data. */ + len = a->d.size - a->d.len; if (DBG_IOBUF) - log_debug ("iobuf-%d.%d: underflow: req=%lu\n", + log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes)\n", a->no, a->subno, (ulong) len); - rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, - a->d.buf, &len); + if (len == 0) + /* There is no space for more data. Don't bother calling + A->FILTER. */ + rc = 0; + else + rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, + &a->d.buf[a->d.len], &len); + a->d.len += len; + if (DBG_IOBUF) - { - log_debug ("iobuf-%d.%d: underflow: got=%lu rc=%d\n", - a->no, a->subno, (ulong) len, rc); + log_debug ("iobuf-%d.%d: A->FILTER() returned rc=%d (%s), read %lu bytes\n", + a->no, a->subno, + rc, rc == 0 ? "ok" : rc == -1 ? "EOF" : gpg_strerror (rc), + (ulong) len); /* if( a->no == 1 ) */ /* log_hexdump (" data:", a->d.buf, len); */ - } - if (a->use == IOBUF_INPUT && rc == -1) - { /* EOF: we can remove the filter */ + + if (rc == -1) + /* EOF. */ + { size_t dummy_len = 0; - /* and tell the filter to free itself */ + /* Tell the filter to free itself */ if ((rc = a->filter (a->filter_ov, IOBUFCTRL_FREE, a->chain, NULL, &dummy_len))) log_error ("IOBUFCTRL_FREE failed: %s\n", gpg_strerror (rc)); + + /* Free everything except for the internal buffer. */ if (a->filter_ov && a->filter_ov_owner) - { - xfree (a->filter_ov); - a->filter_ov = NULL; - } - a->filter = NULL; + xfree (a->filter_ov); a->filter_ov = NULL; + a->filter = NULL; a->filter_eof = 1; - if (!len && a->chain) + + if (a->d.len == 0 && a->chain) + /* We don't need to keep this filter around at all: + + - we got an EOF + - we have no buffered data + - a filter follows this one. + + Unlink this filter. */ { iobuf_t b = a->chain; if (DBG_IOBUF) - log_debug ("iobuf-%d.%d: pop in underflow (!len)\n", + log_debug ("iobuf-%d.%d: pop in underflow (nothing buffered, got EOF)\n", a->no, a->subno); xfree (a->d.buf); xfree (a->real_fname); memcpy (a, b, sizeof *a); xfree (b); + print_chain (a); + + return -1; } + else if (a->d.len == 0) + /* We can't unlink this filter (it is the only one in the + pipeline), but we can immediately return EOF. */ + return -1; } else if (rc) - a->error = rc; - - if (!len) + /* Record the error. */ { - if (DBG_IOBUF) - log_debug ("iobuf-%d.%d: underflow: eof\n", a->no, a->subno); - return -1; + a->error = rc; + + if (a->d.len == 0) + /* There is no buffered data. Immediately return EOF. */ + return -1; } - a->d.len = len; - a->d.start = 0; - return a->d.buf[a->d.start++]; - } - else - { - if (DBG_IOBUF) - log_debug ("iobuf-%d.%d: underflow: eof (no filter)\n", - a->no, a->subno); - return -1; /* no filter; return EOF */ } + + assert (a->d.start <= a->d.len); + if (a->d.start < a->d.len) + return a->d.buf[a->d.start++]; + + /* EOF. */ + return -1; }