istream.c revision fb502495e9306fe51e9d2c0019e622a98e9803ab
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "array.h"
d6601a0bc4fd60e58bedbddf2481abd82cba76d7Timo Sirainen#include "str.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "istream-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen i_free(stream->real_stream->iostream.name);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen stream->real_stream->iostream.name = i_strdup(name);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *i_stream_get_name(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream = stream->real_stream->parent;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (stream == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return "";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return stream->real_stream->iostream.name;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen stream->closed = TRUE;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (stream->stream_errno == 0)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen stream->stream_errno = EPIPE;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen}
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenvoid i_stream_destroy(struct istream **stream)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen i_stream_close_full(*stream, FALSE);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen i_stream_unref(stream);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen}
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenvoid i_stream_ref(struct istream *stream)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen io_stream_ref(&stream->real_stream->iostream);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenvoid i_stream_unref(struct istream **stream)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen struct istream_private *_stream = (*stream)->real_stream;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (_stream->iostream.refcount == 1) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->line_str != NULL)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen str_free(&_stream->line_str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen io_stream_unref(&(*stream)->real_stream->iostream);
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen *stream = NULL;
49621bf0ef1d55aaaa2dc7d76011cbfeabdcfbe1Timo Sirainen}
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen#undef i_stream_add_destroy_callback
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen istream_callback_t *callback, void *context)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen callback, context);
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen}
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen void (*callback)())
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen{
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen callback);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainenint i_stream_get_fd(struct istream *stream)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen{
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen struct istream_private *_stream = stream->real_stream;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return _stream->fd;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen}
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainenconst char *i_stream_get_error(struct istream *stream)
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen{
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen struct istream *s;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen /* we'll only return errors for streams that have stream_errno set.
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch we might be returning unintended error otherwise. */
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen if (stream->stream_errno == 0)
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen return "<no error>";
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (s->stream_errno == 0)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen break;
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen if (s->real_stream->iostream.error != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return s->real_stream->iostream.error;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen return strerror(stream->stream_errno);
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen}
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainenvoid i_stream_close(struct istream *stream)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen{
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen i_stream_close_full(stream, TRUE);
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->real_stream->init_buffer_size = size;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen return stream->real_stream->max_buffer_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->real_stream->return_nolf_line = set;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (stream->parent == NULL)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->access_counter++;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen else {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->access_counter =
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->parent->real_stream->access_counter;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenssize_t i_stream_read(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen size_t old_size;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ssize_t ret;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->eof = TRUE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen errno = stream->stream_errno;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen return -1;
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->eof = FALSE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (_stream->parent != NULL)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen old_size = _stream->pos - _stream->skip;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen ret = _stream->read(_stream);
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen switch (ret) {
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen case -2:
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen i_assert(_stream->skip != _stream->pos);
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen break;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen case -1:
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (stream->stream_errno != 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* error handling should be easier if we now just
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen assume the stream is now at EOF */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->eof = TRUE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen errno = stream->stream_errno;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen } else {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_assert(stream->eof);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen break;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen case 0:
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_assert(!stream->blocking);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen break;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen default:
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_assert(ret > 0);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_assert(_stream->skip < _stream->pos);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen break;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen }
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (stream->stream_errno != 0) {
79fff45046397ba48c8693d5f37a1fd93096987fTimo Sirainen /* error handling should be easier if we now just
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen assume the stream is now at EOF. Note that we could get here
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen even if read() didn't return -1, although that's a little
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen bit sloppy istream implementation. */
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen stream->eof = TRUE;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen }
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen i_stream_update(_stream);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen return ret;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen}
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen struct istream_private *stream = istream->real_stream;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen size_t pos;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen ssize_t ret;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen stream->pos -= stream->skip;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->skip = 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (pos > stream->pos)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen ret = 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen else do {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_update(stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -2;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.eof = stream->parent->eof;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* check again, in case the parent stream had been seeked
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen backwards and the previous read() didn't get us far
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enough. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } while (pos <= stream->pos && ret > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (ret == 0 ? 0 : -1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->pos = pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(ret != -1 || stream->istream.eof ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.stream_errno != 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_update(stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t data_size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen data_size = _stream->pos - _stream->skip;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (count <= data_size) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* within buffer */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen stream->v_offset += count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->skip += count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* have to seek forward */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen count -= data_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->skip = _stream->pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->v_offset += data_size;
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (unlikely(stream->closed))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen{
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (stream->parent == NULL)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return TRUE;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (stream->access_counter !=
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen stream->parent->real_stream->access_counter)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return FALSE;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
e30b9e07f9657c35ca09ac36d57d60cbe2ebbc66Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (v_offset >= stream->v_offset &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_can_optimize_seek(_stream))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch stream->eof = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->seek(_stream, v_offset, FALSE);
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_update(_stream);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen{
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen struct istream_private *_stream = stream->real_stream;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (unlikely(stream->closed))
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch return;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch stream->eof = FALSE;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen _stream->seek(_stream, v_offset, TRUE);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen i_stream_update(_stream);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen}
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Boschvoid i_stream_sync(struct istream *stream)
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch{
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen struct istream_private *_stream = stream->real_stream;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen if (unlikely(stream->closed))
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen return;
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->sync != NULL) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen _stream->sync(_stream);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen i_stream_update(_stream);
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen }
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen}
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->stat(_stream, exact) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen *st_r = &_stream->statbuf;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct istream_private *_stream = stream->real_stream;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
b9dc21a94401638c00e40b695998875e1563ce77Timo Sirainen return _stream->get_size(_stream, exact, size_r);
b9dc21a94401638c00e40b695998875e1563ce77Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
27ca6cb0548c6478005c77d04be641356ec7d83cTimo Sirainen{
27ca6cb0548c6478005c77d04be641356ec7d83cTimo Sirainen return i_stream_get_data_size(stream) > 0 || !stream->eof;
11120acd01d43973cd504952d691a2ae1c546ee2Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenbool i_stream_is_eof(struct istream *stream)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (i_stream_get_data_size(stream) == 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen (void)i_stream_read(stream);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return !i_stream_have_bytes_left(stream);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return stream->real_stream->abs_start_offset + stream->v_offset;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen}
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen{
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen char *ret;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen size_t end;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen end = i - 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->line_crlf = TRUE;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen end = i;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen stream->line_crlf = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (stream->w_buffer != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* modify the buffer directly */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen stream->w_buffer[end] = '\0';
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* use a temporary string to return it */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (stream->line_str == NULL)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen stream->line_str = str_new(default_pool, 256);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen str_truncate(stream->line_str, 0);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen end - stream->skip);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen ret = str_c_modifiable(stream->line_str);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (i < stream->pos)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen i++;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.v_offset += i - stream->skip;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen stream->skip = i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen}
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen _stream->return_nolf_line) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* the last line is missing LF and we want to return it. */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return NULL;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenchar *i_stream_next_line(struct istream *stream)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const unsigned char *pos;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (_stream->skip >= _stream->pos)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen return NULL;
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen _stream->pos - _stream->skip);
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen if (pos != NULL) {
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen return i_stream_next_line_finish(_stream,
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen pos - _stream->buffer);
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen } else {
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen return i_stream_last_line(_stream);
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen }
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen}
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainenchar *i_stream_read_next_line(struct istream *stream)
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen{
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen char *line;
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen for (;;) {
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen line = i_stream_next_line(stream);
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen if (line != NULL)
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen break;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen switch (i_stream_read(stream)) {
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen case -2:
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen io_stream_set_error(&stream->real_stream->iostream,
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen "Line is too long (over %"PRIuSIZE_T
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen " bytes at offset %"PRIuUOFF_T")",
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen i_stream_get_data_size(stream), stream->v_offset);
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen stream->stream_errno = errno = ENOBUFS;
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen stream->eof = TRUE;
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen return NULL;
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen case -1:
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen return i_stream_last_line(stream->real_stream);
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen case 0:
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen return NULL;
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen }
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen }
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen return line;
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen}
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen{
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen return stream->real_stream->line_crlf;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream)
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen{
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen if (stream->parent == NULL) {
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen /* the buffer can't point to parent, because it doesn't exist */
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen return FALSE;
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen }
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen if (stream->w_buffer != NULL) {
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen /* we can pretty safely assume that the stream is using its
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen own private buffer, so it can never become invalid. */
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen return FALSE;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen }
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen if (stream->access_counter !=
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen stream->parent->real_stream->access_counter) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen /* parent has been modified behind this stream, we can't trust
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen that our buffer is valid */
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen return TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return i_stream_is_buffer_invalid(stream->parent->real_stream);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenconst unsigned char *
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Siraineni_stream_get_data(struct istream *stream, size_t *size_r)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen{
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen struct istream_private *_stream = stream->real_stream;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (_stream->skip >= _stream->pos) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen *size_r = 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return NULL;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (i_stream_is_buffer_invalid(_stream)) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen /* This stream may be using parent's buffer directly as
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen _stream->buffer, but the parent stream has already been
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen modified indirectly. This means that the buffer might no
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen longer point to where we assume it points to. So we'll
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen just return the stream as empty until it's read again.
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen It's a bit ugly to suddenly drop data from the stream that
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen was already read, but since this happens only with shared
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen parent istreams the caller is hopefully aware enough that
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen something like this might happen. The other solutions would
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen be to a) try to automatically read the data back (but we
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen can't handle errors..) or b) always copy data to stream's
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen own buffer instead of pointing to parent's buffer (but this
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen causes data copying that is nearly always unnecessary). */
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *size_r = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* if we had already read until EOF, mark the stream again as
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen not being at the end of file. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->stream_errno == 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen _stream->skip = _stream->pos = 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen stream->eof = FALSE;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen return NULL;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *size_r = _stream->pos - _stream->skip;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return _stream->buffer + _stream->skip;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen}
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainensize_t i_stream_get_data_size(struct istream *stream)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen size_t size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)i_stream_get_data(stream, &size);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return size;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen size_t *size_r)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct istream_private *_stream = stream->real_stream;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen *size_r = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return NULL;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen *size_r = _stream->pos - _stream->skip;
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen return _stream->w_buffer + _stream->skip;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen size_t *size_r, size_t threshold)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ssize_t ret = 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen bool read_more = FALSE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen do {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (*size_r > threshold)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return 1;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen /* we need more data */
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen ret = i_stream_read(stream);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (ret > 0)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen read_more = TRUE;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen } while (ret > 0);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (ret == -2)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return -2;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (ret == 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* need to read more */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(!stream->blocking);
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen return 0;
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen }
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen if (stream->eof) {
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen if (read_more) {
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen /* we read at least some new data */
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen return 0;
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen }
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen } else {
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen i_assert(stream->stream_errno != 0);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return -1;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenvoid i_stream_compress(struct istream_private *stream)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen stream->pos - stream->skip);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen stream->pos -= stream->skip;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen stream->skip = 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen size_t old_size;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(stream->max_buffer_size > 0);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen old_size = stream->buffer_size;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen stream->buffer_size = stream->pos + bytes;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen stream->buffer_size = stream->init_buffer_size;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen else
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen if (stream->buffer_size > stream->max_buffer_size)
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen stream->buffer_size = stream->max_buffer_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->buffer_size <= old_size)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen stream->buffer_size = old_size;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen else {
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen stream->buffer_size);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen stream->buffer = stream->w_buffer;
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen size_t wanted_size, size_t *size_r)
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(wanted_size > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (stream->skip > 0) {
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen /* remove the unused bytes from beginning of buffer */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_compress(stream);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen } else if (stream->max_buffer_size == 0 ||
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
b00c511e4675c4a1270d92924fc445cfb8631cf3Timo Sirainen /* buffer is full - grow it */
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen }
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen }
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen *size_r = stream->buffer_size - stream->pos;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (stream->try_alloc_limit > 0 &&
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen *size_r > stream->try_alloc_limit)
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen *size_r = stream->try_alloc_limit;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return *size_r > 0;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen}
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen{
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen size_t old_size, avail_size;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (avail_size < size) {
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen old_size = stream->buffer_size;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->buffer_size);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen stream->buffer = stream->w_buffer;
8c81109dca287f1830aac57bae61e57260248941Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen i_assert(avail_size >= size);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen }
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen return stream->w_buffer + stream->pos;
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen}
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t size)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen struct istream_private *stream = _stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t size2;
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_stream_try_alloc(stream, size, &size2);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen if (size > size2)
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen return FALSE;
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen stream->pos += size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen}
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!pending)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen while (stream->real_stream->parent != NULL) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_assert(stream->real_stream->io == NULL);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen stream = stream->real_stream->parent;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->real_stream->io != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_set_pending(stream->real_stream->io);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_switch_ioloop(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
1e40531c1de45bc87e72a9d5866ff2af79b63cebTimo Sirainen do {
1e40531c1de45bc87e72a9d5866ff2af79b63cebTimo Sirainen if (stream->real_stream->switch_ioloop != NULL)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->real_stream->switch_ioloop(stream->real_stream);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream = stream->real_stream->parent;
691f802ef6ec2105079d420ba26b21088402c6daTimo Sirainen } while (stream != NULL);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenvoid i_stream_set_io(struct istream *stream, struct io *io)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen while (stream->real_stream->parent != NULL) {
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch i_assert(stream->real_stream->io == NULL);
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen stream = stream->real_stream->parent;
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch }
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
a020eb653b2620a989e4795adceb6136037327b2Timo Sirainen i_assert(stream->real_stream->io == NULL);
a020eb653b2620a989e4795adceb6136037327b2Timo Sirainen stream->real_stream->io = io;
a020eb653b2620a989e4795adceb6136037327b2Timo Sirainen}
a020eb653b2620a989e4795adceb6136037327b2Timo Sirainen
a020eb653b2620a989e4795adceb6136037327b2Timo Sirainenvoid i_stream_unset_io(struct istream *stream, struct io *io)
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen{
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen while (stream->real_stream->parent != NULL) {
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen i_assert(stream->real_stream->io == NULL);
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen stream = stream->real_stream->parent;
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen }
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen i_assert(stream->real_stream->io == io);
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen stream->real_stream->io = NULL;
c977ee6ce06cbc0b4668fde1ec34f2f5e1773684Timo Sirainen}
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainenstatic void
8cca3b43b28365cfee4dc733c00caaeab8ecd2adTimo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
8cca3b43b28365cfee4dc733c00caaeab8ecd2adTimo Sirainen size_t max_size)
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen _stream->max_buffer_size = max_size;
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen if (_stream->parent != NULL)
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen}
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainenstatic void i_stream_default_close(struct iostream_private *stream,
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen bool close_parent)
c56500d4363beba4ffa954069ab30f4401849156Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen if (close_parent && _stream->parent != NULL)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen i_stream_close(_stream->parent);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen}
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen{
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen i_free(_stream->w_buffer);
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen if (_stream->parent != NULL)
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen i_stream_unref(&_stream->parent);
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen}
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainenstatic void
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Siraineni_stream_default_seek_seekable(struct istream_private *stream,
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen{
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen stream->istream.v_offset = v_offset;
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen stream->skip = stream->pos = 0;
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen}
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_default_seek_nonseekable(struct istream_private *stream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk{
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen size_t available;
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen
2e441a8e3d694820a82d887dcdc4d2d568e428a8Timo Sirainen if (stream->istream.v_offset > v_offset)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_panic("stream %s doesn't support seeking backwards",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_get_name(&stream->istream));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen while (stream->istream.v_offset < v_offset) {
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen (void)i_stream_read(&stream->istream);
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen available = stream->pos - stream->skip;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen if (available == 0) {
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen if (stream->istream.stream_errno != 0) {
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen /* read failed */
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen return;
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_set_error(&stream->iostream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Can't seek to offset %"PRIuUOFF_T
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ", because we have data only up to offset %"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen PRIuUOFF_T" (eof=%d)", v_offset,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.v_offset, stream->istream.eof);
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Sirainen stream->istream.stream_errno = ESPIPE;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen return;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen }
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen if (available <= v_offset - stream->istream.v_offset)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen i_stream_skip(&stream->istream, available);
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Sirainen else {
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen i_stream_skip(&stream->istream,
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen v_offset - stream->istream.v_offset);
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen }
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen }
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Sirainen}
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Sirainen
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Sirainenstatic int
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Siraineni_stream_default_stat(struct istream_private *stream, bool exact)
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Sirainen{
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen const struct stat *st;
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen if (stream->parent == NULL)
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen return stream->istream.stream_errno == 0 ? 0 : -1;
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0)
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen return -1;
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen stream->statbuf = *st;
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen if (exact && !stream->stream_size_passthrough) {
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen /* exact size is not known, even if parent returned something */
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen stream->statbuf.st_size = -1;
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen }
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen return 0;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen}
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainenstatic int
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Siraineni_stream_default_get_size(struct istream_private *stream,
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen bool exact, uoff_t *size_r)
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen{
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen if (stream->stat(stream, exact) < 0)
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainen return -1;
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen if (stream->statbuf.st_size == -1)
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen return 0;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen *size_r = stream->statbuf.st_size;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen return 1;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen}
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen
38dac3030bdd74acba0a60edd54b2db6d914fde2Timo Sirainenvoid i_stream_init_parent(struct istream_private *_stream,
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen struct istream *parent)
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen{
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen _stream->access_counter = parent->real_stream->access_counter;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen _stream->parent = parent;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen _stream->parent_start_offset = parent->v_offset;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen _stream->parent_expected_offset = parent->v_offset;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen _stream->abs_start_offset = parent->v_offset +
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen parent->real_stream->abs_start_offset;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen /* if parent stream is an istream-error, copy the error */
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen _stream->istream.stream_errno = parent->stream_errno;
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainen _stream->istream.eof = parent->eof;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen i_stream_ref(parent);
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen}
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainenstruct istream *
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen{
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen _stream->fd = fd;
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen if (parent != NULL)
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen i_stream_init_parent(_stream, parent);
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen _stream->istream.real_stream = _stream;
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen if (_stream->iostream.close == NULL)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen _stream->iostream.close = i_stream_default_close;
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen if (_stream->iostream.destroy == NULL)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen _stream->iostream.destroy = i_stream_default_destroy;
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen if (_stream->seek == NULL) {
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen _stream->seek = _stream->istream.seekable ?
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen i_stream_default_seek_seekable :
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen i_stream_default_seek_nonseekable;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (_stream->stat == NULL)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen _stream->stat = i_stream_default_stat;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (_stream->get_size == NULL)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen _stream->get_size = i_stream_default_get_size;
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen _stream->iostream.set_max_buffer_size =
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen i_stream_default_set_max_buffer_size;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (_stream->init_buffer_size == 0)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen _stream->init_buffer_size = I_STREAM_MIN_SIZE;
23152672e3ad7f3512c11df43e8dabba4fe6407dTimo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen _stream->statbuf.st_size = -1;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen _stream->statbuf.st_atime =
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen _stream->statbuf.st_mtime =
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen _stream->statbuf.st_ctime = ioloop_time;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen
8abe071cb14a622b9d84b00a9269f96d01a576f6Timo Sirainen io_stream_init(&_stream->iostream);
8abe071cb14a622b9d84b00a9269f96d01a576f6Timo Sirainen return &_stream->istream;
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen}
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Sirainen
85779ec11f23eb8efeb8993b1e0b9aad62c4122aTimo Sirainenstruct istream *i_stream_create_error(int stream_errno)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen{
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen struct istream_private *stream;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen stream = i_new(struct istream_private, 1);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen stream->istream.closed = TRUE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen stream->istream.readable_fd = FALSE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen stream->istream.blocking = TRUE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen stream->istream.seekable = TRUE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen stream->istream.eof = TRUE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen stream->istream.stream_errno = stream_errno;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen i_stream_create(stream, NULL, -1);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen i_stream_set_name(&stream->istream, "(error)");
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return &stream->istream;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstruct istream *
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Siraineni_stream_create_error_str(int stream_errno, const char *fmt, ...)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
0992011130e9d0a498ca860ddbe4028398a530c5Timo Sirainen struct istream *input;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen va_list args;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen va_start(args, fmt);
0992011130e9d0a498ca860ddbe4028398a530c5Timo Sirainen input = i_stream_create_error(stream_errno);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen io_stream_set_verror(&input->real_stream->iostream, fmt, args);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen va_end(args);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return input;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen