istream.c revision 7a77b948806106b46a33f3e6a3869657f49877fd
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "lib.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "ioloop.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "array.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "str.h"
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen#include "istream-private.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_free(stream->real_stream->iostream.name);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->real_stream->iostream.name = i_strdup(name);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenconst char *i_stream_get_name(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen stream = stream->real_stream->parent;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream == NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return "";
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return stream->real_stream->iostream.name;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->closed = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->stream_errno == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->stream_errno = EPIPE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_destroy(struct istream **stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_close_full(*stream, FALSE);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_unref(stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_ref(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid i_stream_unref(struct istream **stream)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (_stream->iostream.refcount == 1) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (_stream->line_str != NULL)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_free(&_stream->line_str);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen io_stream_unref(&(*stream)->real_stream->iostream);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *stream = NULL;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#undef i_stream_add_destroy_callback
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen istream_callback_t *callback, void *context)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct iostream_destroy_callback *dc;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!array_is_created(&iostream->destroy_callbacks))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_array_init(&iostream->destroy_callbacks, 2);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen dc = array_append_space(&iostream->destroy_callbacks);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen dc->callback = callback;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen dc->context = context;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen void (*callback)())
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct iostream_destroy_callback *dcs;
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen unsigned int i, count;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen dcs = array_get(&iostream->destroy_callbacks, &count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (i = 0; i < count; i++) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (dcs[i].callback == (istream_callback_t *)callback) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen array_delete(&iostream->destroy_callbacks, i, 1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_unreached();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
b104354c4a829e828c361e4a167bf7106d124174Timo Sirainenint i_stream_get_fd(struct istream *stream)
b104354c4a829e828c361e4a167bf7106d124174Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct istream_private *_stream = stream->real_stream;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return _stream->fd;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenconst char *i_stream_get_error(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct istream *s;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* we'll only return errors for streams that have stream_errno set.
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen we might be returning unintended error otherwise. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (stream->stream_errno == 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return "<no error>";
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (s->stream_errno == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (s->real_stream->iostream.error != NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return s->real_stream->iostream.error;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return strerror(stream->stream_errno);
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_close(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_close_full(stream, TRUE);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->real_stream->init_buffer_size = size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return stream->real_stream->max_buffer_size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->real_stream->return_nolf_line = set;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->parent == NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->access_counter++;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->access_counter =
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->parent->real_stream->access_counter;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenssize_t i_stream_read(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *_stream = stream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen size_t old_size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ssize_t ret;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen errno = stream->stream_errno;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->eof = FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (_stream->parent != NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen old_size = _stream->pos - _stream->skip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = _stream->read(_stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen switch (ret) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case -2:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(_stream->skip != _stream->pos);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case -1:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->stream_errno != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* error handling should be easier if we now just
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen assume the stream is now at EOF */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->eof = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen errno = stream->stream_errno;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(stream->eof);
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case 0:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_assert(!stream->blocking);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen default:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(ret > 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(_stream->skip < _stream->pos);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_update(_stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *stream = istream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen size_t pos;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ssize_t ret;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->pos -= stream->skip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->skip = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (pos > stream->pos)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = 0;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen else do {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_update(stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -2;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->istream.eof = stream->parent->eof;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* check again, in case the parent stream had been seeked
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen backwards and the previous read() didn't get us far
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enough. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } while (pos <= stream->pos && ret > 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen (ret == 0 ? 0 : -1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->pos = pos;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(ret != -1 || stream->istream.eof ||
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->istream.stream_errno != 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_update(stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return ret;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen}
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *_stream = stream->real_stream;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen size_t data_size;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen data_size = _stream->pos - _stream->skip;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (count <= data_size) {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen /* within buffer */
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen stream->v_offset += count;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen _stream->skip += count;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen return;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen /* have to seek forward */
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen count -= data_size;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen _stream->skip = _stream->pos;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen stream->v_offset += data_size;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (unlikely(stream->closed))
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen return;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen}
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen{
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (stream->parent == NULL)
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen return TRUE;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (stream->access_counter !=
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen stream->parent->real_stream->access_counter)
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen return FALSE;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen}
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *_stream = stream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (v_offset >= stream->v_offset &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_can_optimize_seek(_stream))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (unlikely(stream->closed))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen stream->eof = FALSE;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen _stream->seek(_stream, v_offset, FALSE);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i_stream_update(_stream);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen}
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen{
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen struct istream_private *_stream = stream->real_stream;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (unlikely(stream->closed))
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen return;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen stream->eof = FALSE;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen _stream->seek(_stream, v_offset, TRUE);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i_stream_update(_stream);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen}
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainenvoid i_stream_sync(struct istream *stream)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen{
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen struct istream_private *_stream = stream->real_stream;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (unlikely(stream->closed))
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen return;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (_stream->sync != NULL) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen _stream->sync(_stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_update(_stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *_stream = stream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (unlikely(stream->closed))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (_stream->stat(_stream, exact) < 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *st_r = &_stream->statbuf;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *_stream = stream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen if (unlikely(stream->closed))
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return _stream->get_size(_stream, exact, size_r);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return i_stream_get_data_size(stream) > 0 || !stream->eof;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenbool i_stream_is_eof(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (i_stream_get_data_size(stream) == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (void)i_stream_read(stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return !i_stream_have_bytes_left(stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen{
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen return stream->real_stream->abs_start_offset + stream->v_offset;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen char *ret;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen size_t end;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r') {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen end = i - 1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->line_crlf = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen end = i;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen stream->line_crlf = FALSE;
31ed209b28f30bcc2ce20de07aaa43d432126e24Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->w_buffer != NULL) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen /* modify the buffer directly */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen stream->w_buffer[end] = '\0';
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* use a temporary string to return it */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->line_str == NULL)
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen stream->line_str = str_new(default_pool, 256);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_truncate(stream->line_str, 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen end - stream->skip);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = str_c_modifiable(stream->line_str);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (i < stream->pos)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i++;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen stream->istream.v_offset += i - stream->skip;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen stream->skip = i;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen return ret;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen}
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen{
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen _stream->return_nolf_line) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen /* the last line is missing LF and we want to return it. */
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen return NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenchar *i_stream_next_line(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *_stream = stream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const unsigned char *pos;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (_stream->skip >= _stream->pos)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen _stream->pos - _stream->skip);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (pos != NULL) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return i_stream_next_line_finish(_stream,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen pos - _stream->buffer);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return i_stream_last_line(_stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenchar *i_stream_read_next_line(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen char *line;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (;;) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen line = i_stream_next_line(stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (line != NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen break;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen switch (i_stream_read(stream)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case -2:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen io_stream_set_error(&stream->real_stream->iostream,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "Line is too long (over %"PRIuSIZE_T
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen " bytes at offset %"PRIuUOFF_T")",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_get_data_size(stream), stream->v_offset);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->stream_errno = errno = ENOBUFS;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->eof = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case -1:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return i_stream_last_line(stream->real_stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen case 0:
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return line;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen{
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen return stream->real_stream->line_crlf;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->parent == NULL) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* the buffer can't point to parent, because it doesn't exist */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->w_buffer != NULL) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we can pretty safely assume that the stream is using its
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen own private buffer, so it can never become invalid. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->access_counter !=
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->parent->real_stream->access_counter) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* parent has been modified behind this stream, we can't trust
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen that our buffer is valid */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return i_stream_is_buffer_invalid(stream->parent->real_stream);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenconst unsigned char *
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Siraineni_stream_get_data(struct istream *stream, size_t *size_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *_stream = stream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (_stream->skip >= _stream->pos) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *size_r = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return NULL;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (i_stream_is_buffer_invalid(_stream)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* This stream may be using parent's buffer directly as
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen _stream->buffer, but the parent stream has already been
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen modified indirectly. This means that the buffer might no
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen longer point to where we assume it points to. So we'll
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen just return the stream as empty until it's read again.
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen It's a bit ugly to suddenly drop data from the stream that
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen was already read, but since this happens only with shared
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen parent istreams the caller is hopefully aware enough that
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen something like this might happen. The other solutions would
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen be to a) try to automatically read the data back (but we
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen can't handle errors..) or b) always copy data to stream's
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen own buffer instead of pointing to parent's buffer (but this
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen causes data copying that is nearly always unnecessary). */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen *size_r = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* if we had already read until EOF, mark the stream again as
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen not being at the end of file. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->stream_errno == 0) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen _stream->skip = _stream->pos = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->eof = FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
08837f59c1466ec0f533f120b167f2a3e87da738Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *size_r = _stream->pos - _stream->skip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return _stream->buffer + _stream->skip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainensize_t i_stream_get_data_size(struct istream *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
115cf0320f679e4e63db25e7f44f47977b8338deTimo Sirainen size_t size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
115cf0320f679e4e63db25e7f44f47977b8338deTimo Sirainen (void)i_stream_get_data(stream, &size);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen size_t *size_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *_stream = stream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
b7c841fd6dc508d87db8b1b64ea1a8f4cb0b8971Timo Sirainen *size_r = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return NULL;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *size_r = _stream->pos - _stream->skip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return _stream->w_buffer + _stream->skip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen size_t *size_r, size_t threshold)
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen{
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen ssize_t ret = 0;
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen bool read_more = FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen do {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*size_r > threshold)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 1;
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we need more data */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = i_stream_read(stream);
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen if (ret > 0)
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen read_more = TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } while (ret > 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ret == -2)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -2;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ret == 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* need to read more */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(!stream->blocking);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (stream->eof) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (read_more) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we read at least some new data */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(stream->stream_errno != 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->pos - stream->skip);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->pos -= stream->skip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->skip = 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen size_t old_size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(stream->max_buffer_size > 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen old_size = stream->buffer_size;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->buffer_size = stream->pos + bytes;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
3a508ab3b10ff08889f3046a6bbf8553b55e3d44Timo Sirainen stream->buffer_size = stream->init_buffer_size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else
cddfd1355db6b60c71d7ee3c0b4f23b3efcc9ad1Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen if (stream->buffer_size > stream->max_buffer_size)
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen stream->buffer_size = stream->max_buffer_size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->buffer_size <= old_size)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->buffer_size = old_size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen stream->buffer_size);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen stream->buffer = stream->w_buffer;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen size_t wanted_size, size_t *size_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(wanted_size > 0);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->skip > 0) {
5caf685b62a30b1f935b80a3f9f1bdcefb63a38cTimo Sirainen /* remove the unused bytes from beginning of buffer */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_compress(stream);
5caf685b62a30b1f935b80a3f9f1bdcefb63a38cTimo Sirainen } else if (stream->max_buffer_size == 0 ||
5caf685b62a30b1f935b80a3f9f1bdcefb63a38cTimo Sirainen stream->buffer_size < stream->max_buffer_size) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* buffer is full - grow it */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *size_r = stream->buffer_size - stream->pos;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (stream->try_alloc_limit > 0 &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *size_r > stream->try_alloc_limit)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *size_r = stream->try_alloc_limit;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return *size_r > 0;
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen}
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen{
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen size_t old_size, avail_size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
be6bde0e1f40db97871b657603188fc9041f1d04Timo Sirainen if (avail_size < size) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen old_size = stream->buffer_size;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->buffer_size);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen stream->buffer = stream->w_buffer;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(avail_size >= size);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen return stream->w_buffer + stream->pos;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen size_t size)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct istream_private *stream = _stream->real_stream;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen size_t size2;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_stream_try_alloc(stream, size, &size2);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (size > size2)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen stream->pos += size;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return TRUE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!pending)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen while (stream->real_stream->parent != NULL) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_assert(stream->real_stream->io == NULL);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen stream = stream->real_stream->parent;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (stream->real_stream->io != NULL)
io_set_pending(stream->real_stream->io);
}
void i_stream_switch_ioloop(struct istream *stream)
{
do {
if (stream->real_stream->switch_ioloop != NULL)
stream->real_stream->switch_ioloop(stream->real_stream);
stream = stream->real_stream->parent;
} while (stream != NULL);
}
void i_stream_set_io(struct istream *stream, struct io *io)
{
while (stream->real_stream->parent != NULL) {
i_assert(stream->real_stream->io == NULL);
stream = stream->real_stream->parent;
}
i_assert(stream->real_stream->io == NULL);
stream->real_stream->io = io;
}
void i_stream_unset_io(struct istream *stream, struct io *io)
{
while (stream->real_stream->parent != NULL) {
i_assert(stream->real_stream->io == NULL);
stream = stream->real_stream->parent;
}
i_assert(stream->real_stream->io == io);
stream->real_stream->io = NULL;
}
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 %s doesn't support seeking backwards",
i_stream_get_name(&stream->istream));
while (stream->istream.v_offset < v_offset) {
(void)i_stream_read(&stream->istream);
available = stream->pos - stream->skip;
if (available == 0) {
if (stream->istream.stream_errno != 0) {
/* read failed */
return;
}
io_stream_set_error(&stream->iostream,
"Can't seek to offset %"PRIuUOFF_T
", because we have data only up to offset %"
PRIuUOFF_T" (eof=%d)", v_offset,
stream->istream.v_offset, stream->istream.eof);
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;
}
void i_stream_init_parent(struct istream_private *_stream,
struct istream *parent)
{
_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);
}
struct istream *
i_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
{
_stream->fd = fd;
if (parent != NULL)
i_stream_init_parent(_stream, 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;
}
struct istream *
i_stream_create_error_str(int stream_errno, const char *fmt, ...)
{
struct istream *input;
va_list args;
va_start(args, fmt);
input = i_stream_create_error(stream_errno);
io_stream_set_verror(&input->real_stream->iostream, fmt, args);
va_end(args);
return input;
}