istream.c revision 5a1b498b646b5c5dbd1b3f3861df766f560578c5
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(stream->real_stream->iostream.name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->real_stream->iostream.name = i_strdup(name);
7888a9d2008eab9985096c46e1da9ee985c22a2aTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenconst char *i_stream_get_name(struct istream *stream)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen{
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen stream = stream->real_stream->parent;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (stream == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return stream->real_stream->iostream.name;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen{
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen stream->closed = TRUE;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen if (stream->stream_errno == 0)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen stream->stream_errno = EPIPE;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen}
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenvoid i_stream_destroy(struct istream **stream)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen{
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen i_stream_close_full(*stream, FALSE);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen i_stream_unref(stream);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid i_stream_ref(struct istream *stream)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen{
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenvoid i_stream_unref(struct istream **stream)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen{
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (_stream->iostream.refcount == 1) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (_stream->line_str != NULL)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen str_free(&_stream->line_str);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen }
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (!io_stream_unref(&(*stream)->real_stream->iostream)) {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen if ((*stream)->real_stream->parent != NULL)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen i_stream_unref(&(*stream)->real_stream->parent);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_stream_free(&(*stream)->real_stream->iostream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *stream = NULL;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen#undef i_stream_add_destroy_callback
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen istream_callback_t *callback, void *context)
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen{
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen callback, context);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen void (*callback)())
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen callback);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen}
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainenint i_stream_get_fd(struct istream *stream)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen{
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen struct istream_private *_stream = stream->real_stream;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return _stream->fd;
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenconst char *i_stream_get_error(struct istream *stream)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct istream *s;
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen /* we'll only return errors for streams that have stream_errno set or
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen that have reached EOF. we might be returning unintended error
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen otherwise. */
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (stream->stream_errno == 0)
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen return stream->eof ? "EOF" : "<no error>";
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (s->stream_errno == 0)
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen break;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen if (s->real_stream->iostream.error != NULL)
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen return s->real_stream->iostream.error;
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen }
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen return strerror(stream->stream_errno);
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen}
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainenvoid i_stream_close(struct istream *stream)
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen{
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen i_stream_close_full(stream, TRUE);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen}
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen{
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen stream->real_stream->init_buffer_size = size;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen}
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen{
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen}
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen{
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen return stream->real_stream->max_buffer_size;
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen{
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen stream->real_stream->return_nolf_line = set;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen}
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainenvoid i_stream_set_persistent_buffers(struct istream *stream, bool set)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen{
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen do {
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen stream->real_stream->nonpersistent_buffers = !set;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen stream = stream->real_stream->parent;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen } while (stream != NULL);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen}
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen{
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (stream->parent == NULL)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen stream->access_counter++;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen else {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen stream->access_counter =
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen stream->parent->real_stream->access_counter;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen}
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenssize_t i_stream_read(struct istream *stream)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct istream_private *_stream = stream->real_stream;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen size_t old_size;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ssize_t ret;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen stream->eof = TRUE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen errno = stream->stream_errno;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen stream->eof = FALSE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (_stream->parent != NULL)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen old_size = _stream->pos - _stream->skip;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = _stream->read(_stream);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen switch (ret) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen case -2:
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen i_assert(_stream->skip != _stream->pos);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen case -1:
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (stream->stream_errno != 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* error handling should be easier if we now just
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen assume the stream is now at EOF */
e376e08040b5f21ff79a15ae728d2532a34207f6Timo Sirainen stream->eof = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen errno = stream->stream_errno;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_assert(stream->eof);
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen case 0:
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_assert(!stream->blocking);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen default:
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen i_assert(ret > 0);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen i_assert(_stream->skip < _stream->pos);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen break;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen }
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen if (stream->stream_errno != 0) {
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen /* error handling should be easier if we now just
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen assume the stream is now at EOF. Note that we could get here
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen even if read() didn't return -1, although that's a little
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen bit sloppy istream implementation. */
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen stream->eof = TRUE;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen }
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen i_stream_update(_stream);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen /* verify that parents' access_counters are valid. the parent's
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen i_stream_read() should guarantee this. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_assert(!i_stream_is_buffer_invalid(_stream));
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen return ret;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen}
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen{
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen struct istream_private *stream = istream->real_stream;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen size_t pos;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen ssize_t ret;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->pos -= stream->skip;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->skip = 0;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (pos > stream->pos)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen else do {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_stream_update(stream);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen return -2;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->istream.eof = stream->parent->eof;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* check again, in case the parent stream had been seeked
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen backwards and the previous read() didn't get us far
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen enough. */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen } while (pos <= stream->pos && ret > 0);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (ret == 0 ? 0 : -1);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->pos = pos;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen i_assert(ret != -1 || stream->istream.eof ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->istream.stream_errno != 0);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen i_stream_update(stream);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return ret;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct istream_private *_stream = stream->real_stream;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen size_t data_size;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen data_size = _stream->pos - _stream->skip;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (count <= data_size) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* within buffer */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen stream->v_offset += count;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen _stream->skip += count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (_stream->nonpersistent_buffers &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen _stream->skip == _stream->pos) {
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen _stream->skip = _stream->pos = 0;
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen _stream->buffer_size = 0;
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen i_free_and_null(_stream->w_buffer);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen }
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen return;
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen }
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen /* have to seek forward */
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen count -= data_size;
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen _stream->skip = _stream->pos;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->v_offset += data_size;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen if (unlikely(stream->closed))
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen return;
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen}
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (stream->parent == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (stream->access_counter !=
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->parent->real_stream->access_counter)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen{
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen struct istream_private *_stream = stream->real_stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (v_offset >= stream->v_offset &&
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen i_stream_can_optimize_seek(_stream))
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen else {
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen if (unlikely(stream->closed))
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen stream->eof = FALSE;
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen _stream->seek(_stream, v_offset, FALSE);
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen }
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen i_stream_update(_stream);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen}
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen{
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct istream_private *_stream = stream->real_stream;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (unlikely(stream->closed))
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen stream->eof = FALSE;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen _stream->seek(_stream, v_offset, TRUE);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen i_stream_update(_stream);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen}
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenvoid i_stream_sync(struct istream *stream)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen{
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct istream_private *_stream = stream->real_stream;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (unlikely(stream->closed))
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (_stream->sync != NULL) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen _stream->sync(_stream);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen i_stream_update(_stream);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen }
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen}
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen{
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct istream_private *_stream = stream->real_stream;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (unlikely(stream->closed))
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return -1;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (_stream->stat(_stream, exact) < 0)
c680a6b35b459045e92814778908da5a93922107Timo Sirainen return -1;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen *st_r = &_stream->statbuf;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return 0;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen}
c680a6b35b459045e92814778908da5a93922107Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen{
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen struct istream_private *_stream = stream->real_stream;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen
096953143c4032bad154637f687551856f7946cbTimo Sirainen if (unlikely(stream->closed))
096953143c4032bad154637f687551856f7946cbTimo Sirainen return -1;
096953143c4032bad154637f687551856f7946cbTimo Sirainen
096953143c4032bad154637f687551856f7946cbTimo Sirainen return _stream->get_size(_stream, exact, size_r);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return i_stream_get_data_size(stream) > 0 || !stream->eof;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenbool i_stream_is_eof(struct istream *stream)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (i_stream_get_data_size(stream) == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen (void)i_stream_read(stream);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return !i_stream_have_bytes_left(stream);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return stream->real_stream->abs_start_offset + stream->v_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t end;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end = i - 1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen stream->line_crlf = TRUE;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen end = i;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen stream->line_crlf = FALSE;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (stream->w_buffer != NULL) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* modify the buffer directly */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen stream->w_buffer[end] = '\0';
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen } else {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* use a temporary string to return it */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (stream->line_str == NULL)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen stream->line_str = str_new(default_pool, 256);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen str_truncate(stream->line_str, 0);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen end - stream->skip);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ret = str_c_modifiable(stream->line_str);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (i < stream->pos)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i++;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen stream->istream.v_offset += i - stream->skip;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen stream->skip = i;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return ret;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen _stream->return_nolf_line) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* the last line is missing LF and we want to return it. */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return NULL;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenchar *i_stream_next_line(struct istream *stream)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct istream_private *_stream = stream->real_stream;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const unsigned char *pos;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (_stream->skip >= _stream->pos)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return NULL;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen _stream->pos - _stream->skip);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (pos != NULL) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return i_stream_next_line_finish(_stream,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen pos - _stream->buffer);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen } else {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return i_stream_last_line(_stream);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenchar *i_stream_read_next_line(struct istream *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *line;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (;;) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen line = i_stream_next_line(stream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (line != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (i_stream_read(stream)) {
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen case -2:
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen io_stream_set_error(&stream->real_stream->iostream,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen "Line is too long (over %"PRIuSIZE_T
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen " bytes at offset %"PRIuUOFF_T")",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_get_data_size(stream), stream->v_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->stream_errno = errno = ENOBUFS;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->eof = TRUE;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen return NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case -1:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return i_stream_last_line(stream->real_stream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case 0:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return line;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return stream->real_stream->line_crlf;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (stream->parent == NULL) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* the buffer can't point to parent, because it doesn't exist */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return FALSE;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (stream->w_buffer != NULL) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* we can pretty safely assume that the stream is using its
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen own private buffer, so it can never become invalid. */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return FALSE;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (stream->access_counter !=
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen stream->parent->real_stream->access_counter) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* parent has been modified behind this stream, we can't trust
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen that our buffer is valid */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return TRUE;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return i_stream_is_buffer_invalid(stream->parent->real_stream);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenconst unsigned char *
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Siraineni_stream_get_data(struct istream *stream, size_t *size_r)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen struct istream_private *_stream = stream->real_stream;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (_stream->skip >= _stream->pos) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen *size_r = 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return NULL;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (i_stream_is_buffer_invalid(_stream)) {
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen /* This stream may be using parent's buffer directly as
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen _stream->buffer, but the parent stream has already been
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen modified indirectly. This means that the buffer might no
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen longer point to where we assume it points to. So we'll
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen just return the stream as empty until it's read again.
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen It's a bit ugly to suddenly drop data from the stream that
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen was already read, but since this happens only with shared
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen parent istreams the caller is hopefully aware enough that
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen something like this might happen. The other solutions would
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen be to a) try to automatically read the data back (but we
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen can't handle errors..) or b) always copy data to stream's
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen own buffer instead of pointing to parent's buffer (but this
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen causes data copying that is nearly always unnecessary). */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen *size_r = 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* if we had already read until EOF, mark the stream again as
37b805dfb45902b6b41c45482f67e6f98e08b0a3Timo Sirainen not being at the end of file. */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (stream->stream_errno == 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen _stream->skip = _stream->pos = 0;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen stream->eof = FALSE;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return NULL;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen *size_r = _stream->pos - _stream->skip;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return _stream->buffer + _stream->skip;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainensize_t i_stream_get_data_size(struct istream *stream)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen{
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen size_t size;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen (void)i_stream_get_data(stream, &size);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return size;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen size_t *size_r)
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen{
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen struct istream_private *_stream = stream->real_stream;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen *size_r = 0;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return NULL;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen *size_r = _stream->pos - _stream->skip;
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen return _stream->w_buffer + _stream->skip;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen size_t *size_r, size_t threshold)
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen{
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen ssize_t ret = 0;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen bool read_more = FALSE;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen do {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (*size_r > threshold)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return 1;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen /* we need more data */
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen ret = i_stream_read(stream);
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen if (ret > 0)
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen read_more = TRUE;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen } while (ret > 0);
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (ret == -2)
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen return -2;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen if (ret == 0) {
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen /* need to read more */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(!stream->blocking);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (stream->eof) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (read_more) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* we read at least some new data */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen } else {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(stream->stream_errno != 0);
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen }
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen return -1;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen}
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen{
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen stream->pos - stream->skip);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen stream->pos -= stream->skip;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen stream->skip = 0;
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen}
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen{
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen size_t old_size;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(stream->max_buffer_size > 0);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen old_size = stream->buffer_size;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen stream->buffer_size = stream->pos + bytes;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer_size = stream->init_buffer_size;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen else
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (stream->buffer_size > stream->max_buffer_size)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer_size = stream->max_buffer_size;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (stream->buffer_size <= old_size)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer_size = old_size;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen else {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer_size);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer = stream->w_buffer;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen }
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen}
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen size_t wanted_size, size_t *size_r)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen{
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen i_assert(wanted_size > 0);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (stream->skip > 0) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen /* remove the unused bytes from beginning of buffer */
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen i_stream_compress(stream);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen } else if (stream->max_buffer_size == 0 ||
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen /* buffer is full - grow it */
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen }
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen }
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen *size_r = stream->buffer_size - stream->pos;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (stream->try_alloc_limit > 0 &&
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen *size_r > stream->try_alloc_limit)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen *size_r = stream->try_alloc_limit;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen return *size_r > 0;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen}
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen{
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen size_t old_size, avail_size;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (avail_size < size) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen old_size = stream->buffer_size;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen stream->buffer_size);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen stream->buffer = stream->w_buffer;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen i_assert(avail_size >= size);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen }
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen return stream->w_buffer + stream->pos;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen size_t size)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct istream_private *stream = _stream->real_stream;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen size_t size2;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_stream_try_alloc(stream, size, &size2);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (size > size2)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return FALSE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen stream->pos += size;
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen return TRUE;
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!pending)
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen return;
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen while (stream->real_stream->parent != NULL) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_assert(stream->real_stream->io == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream = stream->real_stream->parent;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen }
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (stream->real_stream->io != NULL)
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen io_set_pending(stream->real_stream->io);
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen}
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid i_stream_switch_ioloop(struct istream *stream)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen do {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (stream->real_stream->switch_ioloop != NULL)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen stream->real_stream->switch_ioloop(stream->real_stream);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen stream = stream->real_stream->parent;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen } while (stream != NULL);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid i_stream_set_io(struct istream *stream, struct io *io)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen while (stream->real_stream->parent != NULL) {
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen i_assert(stream->real_stream->io == NULL);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen stream = stream->real_stream->parent;
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen }
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainen
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen i_assert(stream->real_stream->io == NULL);
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen stream->real_stream->io = io;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen}
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_unset_io(struct istream *stream, struct io *io)
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen{
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen while (stream->real_stream->parent != NULL) {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen i_assert(stream->real_stream->io == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream = stream->real_stream->parent;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen i_assert(stream->real_stream->io == io);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen stream->real_stream->io = NULL;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainenstatic void
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen size_t max_size)
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen{
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen _stream->max_buffer_size = max_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (_stream->parent != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainenstatic void i_stream_default_close(struct iostream_private *stream,
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen bool close_parent)
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen{
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen if (close_parent && _stream->parent != NULL)
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen i_stream_close(_stream->parent);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_free(_stream->w_buffer);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (_stream->parent != NULL)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_stream_unref(&_stream->parent);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Siraineni_stream_default_seek_seekable(struct istream_private *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->istream.v_offset = v_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->skip = stream->pos = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_default_seek_nonseekable(struct istream_private *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t available;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen if (stream->istream.v_offset > v_offset)
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen i_panic("stream %s doesn't support seeking backwards",
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen i_stream_get_name(&stream->istream));
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (stream->istream.v_offset < v_offset) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)i_stream_read(&stream->istream);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen available = stream->pos - stream->skip;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (available == 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (stream->istream.stream_errno != 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* read failed */
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen return;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen }
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen io_stream_set_error(&stream->iostream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Can't seek to offset %"PRIuUOFF_T
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen ", because we have data only up to offset %"
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen PRIuUOFF_T" (eof=%d)", v_offset,
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen stream->istream.v_offset, stream->istream.eof);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen stream->istream.stream_errno = ESPIPE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen }
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (available <= v_offset - stream->istream.v_offset)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_skip(&stream->istream, available);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen i_stream_skip(&stream->istream,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen v_offset - stream->istream.v_offset);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenstatic int
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Siraineni_stream_default_stat(struct istream_private *stream, bool exact)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen const struct stat *st;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (stream->parent == NULL)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return stream->istream.stream_errno == 0 ? 0 : -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen stream->statbuf = *st;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (exact && !stream->stream_size_passthrough) {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen /* 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) {
stream->istream.stream_errno = stream->parent->stream_errno;
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;
}