istream.c revision 7af4788b402346c94496095dd819f95ce03fe431
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "str.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "istream-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free(stream->real_stream->iostream.name);
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *i_stream_get_name(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream = stream->real_stream->parent;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return "";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return stream->real_stream->iostream.name;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->closed = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->stream_errno == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->stream_errno = EPIPE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_destroy(struct istream **stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen i_stream_close_full(*stream, FALSE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_unref(stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_ref(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_unref(struct istream **stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->iostream.refcount == 1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->line_str != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_free(&_stream->line_str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_unref(&(*stream)->real_stream->iostream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *stream = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#undef i_stream_set_destroy_callback
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_set_destroy_callback(struct istream *stream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen istream_callback_t *callback, void *context)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen iostream->destroy_callback = callback;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen iostream->destroy_context = context;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_unset_destroy_callback(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen iostream->destroy_callback = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen iostream->destroy_context = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenint i_stream_get_fd(struct istream *stream)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen struct istream_private *_stream = stream->real_stream;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return _stream->fd;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen}
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenvoid i_stream_close(struct istream *stream)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_close_full(stream, TRUE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->real_stream->init_buffer_size = size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return stream->real_stream->max_buffer_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->real_stream->return_nolf_line = set;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->parent == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->access_counter++;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->access_counter =
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen stream->parent->real_stream->access_counter;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen}
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainenssize_t i_stream_read(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t old_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ssize_t ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen errno = stream->stream_errno;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->eof = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->stream_errno = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->parent != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_size = _stream->pos - _stream->skip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = _stream->read(_stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen switch (ret) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case -2:
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen i_assert(_stream->skip != _stream->pos);
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen break;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen case -1:
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen if (stream->stream_errno != 0) {
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* error handling should be easier if we now just
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen assume the stream is now at EOF */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->eof = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen errno = stream->stream_errno;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(stream->eof);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 0:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(!stream->blocking);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(ret > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(_stream->skip < _stream->pos);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_update(_stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *stream = istream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ssize_t ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->pos -= stream->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->skip = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (pos > stream->pos)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else do {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -2;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.eof = stream->parent->eof;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* check again, in case the parent stream had been seeked
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen backwards and the previous read() didn't get us far
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enough. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } while (pos <= stream->pos && ret > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen (ret == 0 ? 0 : -1);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen stream->pos = pos;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen i_assert(ret != -1 || stream->istream.eof ||
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen stream->istream.stream_errno != 0);
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen return ret;
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen}
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct istream_private *_stream = stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t data_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen data_size = _stream->pos - _stream->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (count <= data_size) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* within buffer */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->v_offset += count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->skip += count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* have to seek forward */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen count -= data_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen _stream->skip = _stream->pos;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->v_offset += data_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlikely(stream->closed))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->stream_errno = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->parent == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->access_counter !=
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->parent->real_stream->access_counter)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct istream_private *_stream = stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (v_offset >= stream->v_offset &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_can_optimize_seek(_stream))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlikely(stream->closed))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->eof = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen _stream->seek(_stream, v_offset, FALSE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_update(_stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct istream_private *_stream = stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlikely(stream->closed))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->eof = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen _stream->seek(_stream, v_offset, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_update(_stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid i_stream_sync(struct istream *stream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct istream_private *_stream = stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlikely(stream->closed))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (_stream->sync != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen _stream->sync(_stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_update(_stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct istream_private *_stream = stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlikely(stream->closed))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->stat(_stream, exact) < 0)
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen return -1;
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen *st_r = &_stream->statbuf;
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return _stream->get_size(_stream, exact, size_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenbool i_stream_have_bytes_left(const struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return !stream->eof || _stream->skip != _stream->pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainenbool i_stream_is_eof(struct istream *stream)
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen{
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen const struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->skip == _stream->pos)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)i_stream_read(stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return !i_stream_have_bytes_left(stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return stream->real_stream->abs_start_offset + stream->v_offset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen char *ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t end;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen end = i - 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->line_crlf = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen end = i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->line_crlf = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->w_buffer != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* modify the buffer directly */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->w_buffer[end] = '\0';
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* use a temporary string to return it */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->line_str == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->line_str = str_new(default_pool, 256);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_truncate(stream->line_str, 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen end - stream->skip);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = str_c_modifiable(stream->line_str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (i < stream->pos)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->istream.v_offset += i - stream->skip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->skip = i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->return_nolf_line) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* the last line is missing LF and we want to return it. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenchar *i_stream_next_line(struct istream *stream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const unsigned char *pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->skip >= _stream->pos) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!unlikely(stream->closed))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->stream_errno = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen _stream->pos - _stream->skip);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (pos != NULL) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return i_stream_next_line_finish(_stream,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen pos - _stream->buffer);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen } else {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return i_stream_last_line(_stream);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen}
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenchar *i_stream_read_next_line(struct istream *stream)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen char *line;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen for (;;) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen line = i_stream_next_line(stream);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (line != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (i_stream_read(stream)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case -2:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->stream_errno = ENOBUFS;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->eof = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case -1:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return i_stream_last_line(stream->real_stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 0:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return line;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return stream->real_stream->line_crlf;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenconst unsigned char *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Siraineni_stream_get_data(const struct istream *stream, size_t *size_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct istream_private *_stream = stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (_stream->skip >= _stream->pos) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *size_r = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *size_r = _stream->pos - _stream->skip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return _stream->buffer + _stream->skip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainensize_t i_stream_get_data_size(const struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->skip >= _stream->pos)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return _stream->pos - _stream->skip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned char *i_stream_get_modifiable_data(const struct istream *stream,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t *size_r)
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen{
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen const struct istream_private *_stream = stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen *size_r = 0;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen return NULL;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *size_r = _stream->pos - _stream->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return _stream->w_buffer + _stream->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t *size_r, size_t threshold)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ssize_t ret = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool read_more = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen do {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*size_r > threshold)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we need more data */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = i_stream_read(stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen read_more = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } while (ret > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret == -2)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -2;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* need to read more */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(!stream->blocking);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->eof) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (read_more) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we read at least some new data */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen } else {
e4eb49e29197c6783ec93b868100394e189f4e0cTimo Sirainen i_assert(stream->stream_errno != 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->pos - stream->skip);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->pos -= stream->skip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->skip = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t old_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(stream->max_buffer_size > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_size = stream->buffer_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer_size = stream->pos + bytes;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer_size = stream->init_buffer_size;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen else
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->buffer_size > stream->max_buffer_size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer_size = stream->max_buffer_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->buffer_size <= old_size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer_size = old_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer = stream->w_buffer;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t wanted_size, size_t *size_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(wanted_size > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->skip > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* remove the unused bytes from beginning of buffer */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_compress(stream);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (stream->max_buffer_size == 0 ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* buffer is full - grow it */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *size_r = stream->buffer_size - stream->pos;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->try_alloc_limit > 0 &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *size_r > stream->try_alloc_limit)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *size_r = stream->try_alloc_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return *size_r > 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t old_size, avail_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (avail_size < size) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_size = stream->buffer_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->buffer = stream->w_buffer;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(avail_size >= size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return stream->w_buffer + stream->pos;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct istream_private *stream = _stream->real_stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t size2;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_try_alloc(stream, size, &size2);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (size > size2)
return FALSE;
memcpy(stream->w_buffer + stream->pos, data, size);
stream->pos += size;
return TRUE;
}
static void
i_stream_default_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
struct istream_private *_stream = (struct istream_private *)stream;
_stream->max_buffer_size = max_size;
if (_stream->parent != NULL)
i_stream_set_max_buffer_size(_stream->parent, max_size);
}
static void i_stream_default_close(struct iostream_private *stream,
bool close_parent)
{
struct istream_private *_stream = (struct istream_private *)stream;
if (close_parent && _stream->parent != NULL)
i_stream_close(_stream->parent);
}
static void i_stream_default_destroy(struct iostream_private *stream)
{
struct istream_private *_stream = (struct istream_private *)stream;
i_free(_stream->w_buffer);
if (_stream->parent != NULL)
i_stream_unref(&_stream->parent);
}
static void
i_stream_default_seek_seekable(struct istream_private *stream,
uoff_t v_offset, bool mark ATTR_UNUSED)
{
stream->istream.v_offset = v_offset;
stream->skip = stream->pos = 0;
}
void i_stream_default_seek_nonseekable(struct istream_private *stream,
uoff_t v_offset, bool mark ATTR_UNUSED)
{
size_t available;
if (stream->istream.v_offset > v_offset)
i_panic("stream doesn't support seeking backwards");
while (stream->istream.v_offset < v_offset) {
(void)i_stream_read(&stream->istream);
available = stream->pos - stream->skip;
if (available == 0) {
stream->istream.stream_errno = ESPIPE;
return;
}
if (available <= v_offset - stream->istream.v_offset)
i_stream_skip(&stream->istream, available);
else {
i_stream_skip(&stream->istream,
v_offset - stream->istream.v_offset);
}
}
}
static int
i_stream_default_stat(struct istream_private *stream, bool exact)
{
const struct stat *st;
if (stream->parent == NULL)
return stream->istream.stream_errno == 0 ? 0 : -1;
if (i_stream_stat(stream->parent, exact, &st) < 0)
return -1;
stream->statbuf = *st;
if (exact && !stream->stream_size_passthrough) {
/* exact size is not known, even if parent returned something */
stream->statbuf.st_size = -1;
}
return 0;
}
static int
i_stream_default_get_size(struct istream_private *stream,
bool exact, uoff_t *size_r)
{
if (stream->stat(stream, exact) < 0)
return -1;
if (stream->statbuf.st_size == -1)
return 0;
*size_r = stream->statbuf.st_size;
return 1;
}
struct istream *
i_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
{
_stream->fd = fd;
if (parent != NULL) {
_stream->access_counter = parent->real_stream->access_counter;
_stream->parent = parent;
_stream->parent_start_offset = parent->v_offset;
_stream->parent_expected_offset = parent->v_offset;
_stream->abs_start_offset = parent->v_offset +
parent->real_stream->abs_start_offset;
/* if parent stream is an istream-error, copy the error */
_stream->istream.stream_errno = parent->stream_errno;
_stream->istream.eof = parent->eof;
i_stream_ref(parent);
}
_stream->istream.real_stream = _stream;
if (_stream->iostream.close == NULL)
_stream->iostream.close = i_stream_default_close;
if (_stream->iostream.destroy == NULL)
_stream->iostream.destroy = i_stream_default_destroy;
if (_stream->seek == NULL) {
_stream->seek = _stream->istream.seekable ?
i_stream_default_seek_seekable :
i_stream_default_seek_nonseekable;
}
if (_stream->stat == NULL)
_stream->stat = i_stream_default_stat;
if (_stream->get_size == NULL)
_stream->get_size = i_stream_default_get_size;
if (_stream->iostream.set_max_buffer_size == NULL) {
_stream->iostream.set_max_buffer_size =
i_stream_default_set_max_buffer_size;
}
if (_stream->init_buffer_size == 0)
_stream->init_buffer_size = I_STREAM_MIN_SIZE;
memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
_stream->statbuf.st_size = -1;
_stream->statbuf.st_atime =
_stream->statbuf.st_mtime =
_stream->statbuf.st_ctime = ioloop_time;
io_stream_init(&_stream->iostream);
return &_stream->istream;
}
struct istream *i_stream_create_error(int stream_errno)
{
struct istream_private *stream;
stream = i_new(struct istream_private, 1);
stream->istream.closed = TRUE;
stream->istream.readable_fd = FALSE;
stream->istream.blocking = TRUE;
stream->istream.seekable = TRUE;
stream->istream.eof = TRUE;
stream->istream.stream_errno = stream_errno;
i_stream_create(stream, NULL, -1);
i_stream_set_name(&stream->istream, "(error)");
return &stream->istream;
}