diff options
Diffstat (limited to 'crypto/bio/bf_readbuff.c')
-rw-r--r-- | crypto/bio/bf_readbuff.c | 92 |
1 files changed, 56 insertions, 36 deletions
diff --git a/crypto/bio/bf_readbuff.c b/crypto/bio/bf_readbuff.c index 673d592ec0..135ccef83b 100644 --- a/crypto/bio/bf_readbuff.c +++ b/crypto/bio/bf_readbuff.c @@ -57,7 +57,7 @@ static int readbuffer_new(BIO *bi) if (ctx == NULL) return 0; ctx->ibuf_size = DEFAULT_BUFFER_SIZE; - ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + ctx->ibuf = OPENSSL_zalloc(DEFAULT_BUFFER_SIZE); if (ctx->ibuf == NULL) { OPENSSL_free(ctx); return 0; @@ -220,6 +220,7 @@ static int readbuffer_gets(BIO *b, char *buf, int size) BIO_F_BUFFER_CTX *ctx; int num = 0, num_chars, found_newline; char *p; + int i, j; if (size == 0) return 0; @@ -227,42 +228,61 @@ static int readbuffer_gets(BIO *b, char *buf, int size) ctx = (BIO_F_BUFFER_CTX *)b->ptr; BIO_clear_retry_flags(b); - for (;;) { - if (ctx->ibuf_len > 0) { - p = &(ctx->ibuf[ctx->ibuf_off]); - found_newline = 0; - for (num_chars = 0; - (num_chars < ctx->ibuf_len) && (num_chars < size); - num_chars++) { - *(buf++) = p[num_chars]; - if (p[num_chars] == '\n') { - found_newline = 1; - num_chars++; - break; - } - } - num += num_chars; - size -= num_chars; - ctx->ibuf_len -= num_chars; - ctx->ibuf_off += num_chars; - if (found_newline || size == 0) { - *buf = '\0'; - return num; - } - } else { - /* read another line and resize if we have to */ - if (!readbuffer_resize(ctx, size)) - return 0; - - /* Read another line from the next bio using BIO_gets */ - num_chars = BIO_gets(b->next_bio, ctx->ibuf + ctx->ibuf_off, - 1 + size); - if (num_chars <= 0) { - BIO_copy_next_retry(b); - *buf = '\0'; - return num > 0 ? num : num_chars; + /* If data is already buffered then use this first */ + if (ctx->ibuf_len > 0) { + p = ctx->ibuf + ctx->ibuf_off; + found_newline = 0; + for (num_chars = 0; + (num_chars < ctx->ibuf_len) && (num_chars < size); + num_chars++) { + *buf++ = p[num_chars]; + if (p[num_chars] == '\n') { + found_newline = 1; + num_chars++; + break; } - ctx->ibuf_len = num_chars; + } + num += num_chars; + size -= num_chars; + ctx->ibuf_len -= num_chars; + ctx->ibuf_off += num_chars; + if (found_newline || size == 0) { + *buf = '\0'; + return num; } } + /* + * If there is no buffered data left then read any remaining data from the + * next bio. + */ + + /* Resize if we have to */ + if (!readbuffer_resize(ctx, 1 + size)) + return 0; + /* + * Read more data from the next bio using BIO_read_ex: + * Note we cannot use BIO_gets() here as it does not work on a + * binary stream that contains 0x00. (Since strlen() will stop at + * any 0x00 not at the last read '\n' in a FILE bio). + * Also note that some applications open and close the file bio + * multiple times and need to read the next available block when using + * stdin - so we need to READ one byte at a time! + */ + p = ctx->ibuf + ctx->ibuf_off; + for (i = 0; i < size; ++i) { + j = BIO_read(b->next_bio, p, 1); + if (j <= 0) { + BIO_copy_next_retry(b); + *buf = '\0'; + return num > 0 ? num : j; + } + *buf++ = *p; + num++; + ctx->ibuf_off++; + if (*p == '\n') + break; + ++p; + } + *buf = '\0'; + return num; } |