istream.c revision 5aa1aa87a24ff39d566a3ad90d0f8d054118cfe7
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "ioloop.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "array.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "str.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "memarea.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "istream-private.h"
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_free(stream->real_stream->iostream.name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *i_stream_get_name(struct istream *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen while (stream->real_stream->iostream.name == NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream = stream->real_stream->parent;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (stream == NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return "";
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return stream->real_stream->iostream.name;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen{
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen stream->closed = TRUE;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen if (stream->stream_errno == 0)
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen stream->stream_errno = EPIPE;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainenvoid i_stream_destroy(struct istream **stream)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen if (*stream == NULL)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen return;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_stream_close_full(*stream, FALSE);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_stream_unref(stream);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenvoid i_stream_ref(struct istream *stream)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen{
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen io_stream_ref(&stream->real_stream->iostream);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen}
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid i_stream_unref(struct istream **stream)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct istream_private *_stream;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (*stream == NULL)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen _stream = (*stream)->real_stream;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (_stream->iostream.refcount == 1) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (_stream->line_str != NULL)
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen str_free(&_stream->line_str);
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen i_stream_snapshot_free(&_stream->prev_snapshot);
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (!io_stream_unref(&(*stream)->real_stream->iostream)) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_stream_unref(&(*stream)->real_stream->parent);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen io_stream_free(&(*stream)->real_stream->iostream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen *stream = NULL;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen#undef i_stream_add_destroy_callback
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen istream_callback_t *callback, void *context)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen callback, context);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen void (*callback)())
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen callback);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenint i_stream_get_fd(struct istream *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct istream_private *_stream = stream->real_stream;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return _stream->fd;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *i_stream_get_error(struct istream *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct istream *s;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* we'll only return errors for streams that have stream_errno set or
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen that have reached EOF. we might be returning unintended error
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen otherwise. */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (stream->stream_errno == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return stream->eof ? "EOF" : "<no error>";
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (s->stream_errno == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (s->real_stream->iostream.error != NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return s->real_stream->iostream.error;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen return strerror(stream->stream_errno);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *i_stream_get_disconnect_reason(struct istream *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return io_stream_get_disconnect_reason(stream, NULL);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid i_stream_close(struct istream *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (stream != NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_stream_close_full(stream, TRUE);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen stream->real_stream->init_buffer_size = size;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen size_t max_size = 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen do {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (max_size < stream->real_stream->max_buffer_size)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen max_size = stream->real_stream->max_buffer_size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen stream = stream->real_stream->parent;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } while (stream != NULL);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return max_size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->real_stream->return_nolf_line = set;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainenvoid i_stream_set_persistent_buffers(struct istream *stream, bool set)
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen do {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen stream->real_stream->nonpersistent_buffers = !set;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen stream = stream->real_stream->parent;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } while (stream != NULL);
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen}
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenvoid i_stream_set_blocking(struct istream *stream, bool blocking)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen int prev_fd = -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen do {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->blocking = blocking;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (stream->real_stream->fd != -1 &&
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->real_stream->fd != prev_fd) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen fd_set_nonblock(stream->real_stream->fd, !blocking);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen prev_fd = stream->real_stream->fd;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen }
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen stream = stream->real_stream->parent;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } while (stream != NULL);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic void i_stream_update(struct istream_private *stream)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (stream->parent == NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->access_counter++;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->access_counter =
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->parent->real_stream->access_counter;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic bool snapshot_has_memarea(struct istream_snapshot *snapshot,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct memarea *memarea)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen{
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (snapshot->old_memarea == memarea)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return TRUE;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (snapshot->prev_snapshot != NULL)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return snapshot_has_memarea(snapshot->prev_snapshot, memarea);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return FALSE;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen}
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainenstruct istream_snapshot *
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Siraineni_stream_default_snapshot(struct istream_private *stream,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen struct istream_snapshot *prev_snapshot)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen{
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen struct istream_snapshot *snapshot;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (stream->memarea != NULL) {
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (prev_snapshot != NULL) {
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (snapshot_has_memarea(prev_snapshot, stream->memarea))
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return prev_snapshot;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen }
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen /* This stream has a memarea. Reference it, so we can later on
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen rollback if needed. */
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen snapshot = i_new(struct istream_snapshot, 1);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen snapshot->old_memarea = stream->memarea;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen snapshot->prev_snapshot = prev_snapshot;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen memarea_ref(snapshot->old_memarea);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return snapshot;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (stream->parent == NULL) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_panic("%s is missing istream.snapshot() implementation",
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_stream_get_name(&stream->istream));
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen struct istream_private *_parent_stream =
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen stream->parent->real_stream;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return _parent_stream->snapshot(_parent_stream, prev_snapshot);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen}
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenvoid i_stream_snapshot_free(struct istream_snapshot **_snapshot)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen{
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen struct istream_snapshot *snapshot = *_snapshot;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (*_snapshot == NULL)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen *_snapshot = NULL;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_stream_snapshot_free(&snapshot->prev_snapshot);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (snapshot->old_memarea != NULL)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen memarea_unref(&snapshot->old_memarea);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_free(snapshot);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen}
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenstatic struct istream_snapshot *
94e1adead9faddec88a623485b9999a87b1684faTimo Siraineni_stream_noop_snapshot(struct istream_private *stream ATTR_UNUSED,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen struct istream_snapshot *prev_snapshot)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen{
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return prev_snapshot;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen}
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenssize_t i_stream_read(struct istream *stream)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen{
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen struct istream_private *_stream = stream->real_stream;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen ssize_t ret;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen#ifdef DEBUG
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen unsigned char prev_buf[4];
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen const unsigned char *prev_data = _stream->buffer;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen size_t prev_skip = _stream->skip, prev_pos = _stream->pos;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen bool invalid = i_stream_is_buffer_invalid(_stream);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_assert(prev_skip <= prev_pos);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (invalid)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen ;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen else if (prev_pos - prev_skip <= 4)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen memcpy(prev_buf, prev_data + prev_skip, prev_pos - prev_skip);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen else {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen memcpy(prev_buf, prev_data + prev_skip, 2);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen memcpy(prev_buf+2, prev_data + prev_pos - 2, 2);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen }
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen#endif
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen _stream->prev_snapshot =
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen _stream->snapshot(_stream, _stream->prev_snapshot);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen ret = i_stream_read_memarea(stream);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (ret > 0)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_stream_snapshot_free(&_stream->prev_snapshot);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen#ifdef DEBUG
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen else if (!invalid) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_assert((_stream->pos - _stream->skip) == (prev_pos - prev_skip));
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (prev_pos - prev_skip <= 4)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_assert(memcmp(prev_buf, prev_data + prev_skip, prev_pos - prev_skip) == 0);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen else {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen i_assert(memcmp(prev_buf, prev_data + prev_skip, 2) == 0);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(memcmp(prev_buf+2, prev_data + prev_pos - 2, 2) == 0);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen#endif
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainenssize_t i_stream_read_memarea(struct istream *stream)
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen{
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen struct istream_private *_stream = stream->real_stream;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen size_t old_size;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen ssize_t ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->eof = TRUE;
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen errno = stream->stream_errno;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen stream->eof = FALSE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (_stream->parent != NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen old_size = _stream->pos - _stream->skip;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = _stream->read(_stream);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen switch (ret) {
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen case -2:
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen i_assert(_stream->skip != _stream->pos);
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen break;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen case -1:
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (stream->stream_errno != 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* error handling should be easier if we now just
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen assume the stream is now at EOF */
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen stream->eof = TRUE;
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen errno = stream->stream_errno;
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen } else {
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen i_assert(stream->eof);
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen }
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen break;
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen case 0:
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(!stream->blocking);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen default:
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen i_assert(ret > 0);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(_stream->skip < _stream->pos);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (stream->stream_errno != 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* error handling should be easier if we now just
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen assume the stream is now at EOF. Note that we could get here
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen even if read() didn't return -1, although that's a little
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen bit sloppy istream implementation. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->eof = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_stream_update(_stream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* verify that parents' access_counters are valid. the parent's
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_stream_read() should guarantee this. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(!i_stream_is_buffer_invalid(_stream));
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint i_stream_read_more_memarea(struct istream *stream,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const unsigned char **data_r, size_t *size_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *data_r = i_stream_get_data(stream, size_r);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (*size_r > 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 1;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen int ret = i_stream_read_memarea(stream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *data_r = i_stream_get_data(stream, size_r);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct istream_private *stream = istream->real_stream;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen size_t pos;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen ssize_t ret;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen stream->pos -= stream->skip;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen stream->skip = 0;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if (pos > stream->pos)
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen ret = 0;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen else do {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if ((ret = i_stream_read_memarea(stream->parent)) == -2) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen i_stream_update(stream);
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen return -2;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen }
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen stream->istream.eof = stream->parent->eof;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* check again, in case the parent stream had been seeked
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backwards and the previous read() didn't get us far
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen enough. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } while (pos <= stream->pos && ret > 0);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen (ret == 0 ? 0 : -1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->pos = pos;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(ret != -1 || stream->istream.eof ||
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->istream.stream_errno != 0);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen i_stream_update(stream);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid i_stream_free_buffer(struct istream_private *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (stream->memarea != NULL) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen memarea_unref(&stream->memarea);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen stream->w_buffer = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else if (stream->w_buffer != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_free_and_null(stream->w_buffer);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* don't know how to free it */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->buffer_size = 0;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct istream_private *_stream = stream->real_stream;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen size_t data_size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen data_size = _stream->pos - _stream->skip;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (count <= data_size) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* within buffer */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->v_offset += count;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen _stream->skip += count;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (_stream->nonpersistent_buffers &&
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen _stream->skip == _stream->pos) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen _stream->skip = _stream->pos = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen i_stream_free_buffer(_stream);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* have to seek forward */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen count -= data_size;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen _stream->skip = _stream->pos;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->v_offset += data_size;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (stream->parent == NULL)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return TRUE;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (stream->access_counter !=
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->parent->real_stream->access_counter)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return FALSE;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct istream_private *_stream = stream->real_stream;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (v_offset >= stream->v_offset &&
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_stream_can_optimize_seek(_stream))
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->eof = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen stream->eof = FALSE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen _stream->seek(_stream, v_offset, FALSE);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_stream_update(_stream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct istream_private *_stream = stream->real_stream;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->eof = FALSE;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen _stream->seek(_stream, v_offset, TRUE);
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen i_stream_update(_stream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid i_stream_sync(struct istream *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct istream_private *_stream = stream->real_stream;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (_stream->sync != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen _stream->sync(_stream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_stream_update(_stream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct istream_private *_stream = stream->real_stream;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (_stream->stat(_stream, exact) < 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->eof = TRUE;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen *st_r = &_stream->statbuf;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct istream_private *_stream = stream->real_stream;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen int ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if ((ret = _stream->get_size(_stream, exact, size_r)) < 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->eof = TRUE;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen return ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen{
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen return i_stream_get_data_size(stream) > 0 || !stream->eof;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenbool i_stream_read_eof(struct istream *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (i_stream_get_data_size(stream) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (void)i_stream_read(stream);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return !i_stream_have_bytes_left(stream);
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen}
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen{
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen uoff_t abs_offset = stream->v_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen while (stream != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen abs_offset += stream->real_stream->start_offset;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen stream = stream->real_stream->parent;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return abs_offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen char *ret;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen size_t end;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (i > 0 && stream->buffer[i-1] == '\r') {
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen end = i - 1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->line_crlf = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen end = i;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen stream->line_crlf = FALSE;
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen }
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen if (stream->buffer == stream->w_buffer) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* modify the buffer directly */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->w_buffer[end] = '\0';
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = (char *)stream->w_buffer + stream->skip;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen /* use a temporary string to return it */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (stream->line_str == NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen stream->line_str = str_new(default_pool, 256);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen str_truncate(stream->line_str, 0);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen end - stream->skip);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen ret = str_c_modifiable(stream->line_str);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (i < stream->pos)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i++;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->istream.v_offset += i - stream->skip;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->skip = i;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen return ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen _stream->return_nolf_line) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* the last line is missing LF and we want to return it. */
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return NULL;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen}
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenchar *i_stream_next_line(struct istream *stream)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen struct istream_private *_stream = stream->real_stream;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen const unsigned char *pos;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (_stream->skip >= _stream->pos)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return NULL;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen _stream->pos - _stream->skip);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (pos != NULL) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return i_stream_next_line_finish(_stream,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen pos - _stream->buffer);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen } else {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return i_stream_last_line(_stream);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen}
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenchar *i_stream_read_next_line(struct istream *stream)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen char *line;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen for (;;) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen line = i_stream_next_line(stream);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (line != NULL)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen break;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen switch (i_stream_read(stream)) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen case -2:
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen io_stream_set_error(&stream->real_stream->iostream,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen "Line is too long (over %"PRIuSIZE_T
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen " bytes at offset %"PRIuUOFF_T")",
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen i_stream_get_data_size(stream), stream->v_offset);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->stream_errno = errno = ENOBUFS;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->eof = TRUE;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return NULL;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen case -1:
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return i_stream_last_line(stream->real_stream);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen case 0:
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return NULL;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return line;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return stream->real_stream->line_crlf;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (stream->parent == NULL) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* the buffer can't point to parent, because it doesn't exist */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return FALSE;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (stream->w_buffer != NULL) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* we can pretty safely assume that the stream is using its
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen own private buffer, so it can never become invalid. */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return FALSE;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (stream->access_counter !=
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->parent->real_stream->access_counter) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* parent has been modified behind this stream, we can't trust
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen that our buffer is valid */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return TRUE;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return i_stream_is_buffer_invalid(stream->parent->real_stream);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenconst unsigned char *
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Siraineni_stream_get_data(struct istream *stream, size_t *size_r)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct istream_private *_stream = stream->real_stream;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (_stream->skip >= _stream->pos) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen *size_r = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return uchar_empty_ptr;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (i_stream_is_buffer_invalid(_stream)) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* This stream may be using parent's buffer directly as
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen _stream->buffer, but the parent stream has already been
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen modified indirectly. This means that the buffer might no
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen longer point to where we assume it points to. So we'll
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen just return the stream as empty until it's read again.
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen It's a bit ugly to suddenly drop data from the stream that
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen was already read, but since this happens only with shared
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen parent istreams the caller is hopefully aware enough that
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen something like this might happen. The other solutions would
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen be to a) try to automatically read the data back (but we
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen can't handle errors..) or b) always copy data to stream's
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen own buffer instead of pointing to parent's buffer (but this
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen causes data copying that is nearly always unnecessary). */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen *size_r = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* if we had already read until EOF, mark the stream again as
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen not being at the end of file. */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (stream->stream_errno == 0) {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen _stream->skip = _stream->pos = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen stream->eof = FALSE;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return uchar_empty_ptr;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen *size_r = _stream->pos - _stream->skip;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return _stream->buffer + _stream->skip;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainensize_t i_stream_get_data_size(struct istream *stream)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen size_t size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen (void)i_stream_get_data(stream, &size);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return size;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen}
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen size_t *size_r)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct istream_private *_stream = stream->real_stream;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen *size_r = 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen }
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen *size_r = _stream->pos - _stream->skip;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return _stream->w_buffer + _stream->skip;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen size_t *size_r, size_t threshold)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ssize_t ret = 0;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen bool read_more = FALSE;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen do {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen *data_r = i_stream_get_data(stream, size_r);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen if (*size_r > threshold)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen return 1;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* we need more data */
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen ret = i_stream_read(stream);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret > 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen read_more = TRUE;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen } while (ret > 0);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret == -2)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -2;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret == 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* need to read more */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(!stream->blocking);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (stream->eof) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (read_more) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* we read at least some new data */
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen return 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_assert(stream->stream_errno != 0);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen i_assert(stream->memarea == NULL ||
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen memarea_get_refcount(stream->memarea) == 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen if (stream->skip != stream->pos) {
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen stream->pos - stream->skip);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->pos -= stream->skip;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen stream->skip = 0;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic void i_stream_w_buffer_free(void *buf)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen i_free(buf);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenstatic void
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Siraineni_stream_w_buffer_realloc(struct istream_private *stream, size_t old_size)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen void *new_buffer;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (stream->memarea != NULL &&
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen memarea_get_refcount(stream->memarea) == 1) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* Nobody else is referencing the memarea.
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen We can just reallocate it. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen memarea_free_without_callback(&stream->memarea);
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen new_buffer = i_realloc(stream->w_buffer, old_size,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen stream->buffer_size);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen } else {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen new_buffer = i_malloc(stream->buffer_size);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (old_size > 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen i_assert(stream->w_buffer != NULL);
memcpy(new_buffer, stream->w_buffer, old_size);
}
if (stream->memarea != NULL)
memarea_unref(&stream->memarea);
}
stream->w_buffer = new_buffer;
stream->buffer = new_buffer;
stream->memarea = memarea_init(stream->w_buffer, stream->buffer_size,
i_stream_w_buffer_free, new_buffer);
}
void i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
{
size_t old_size, max_size;
old_size = stream->buffer_size;
stream->buffer_size = stream->pos + bytes;
if (stream->buffer_size <= stream->init_buffer_size)
stream->buffer_size = stream->init_buffer_size;
else
stream->buffer_size = nearest_power(stream->buffer_size);
max_size = i_stream_get_max_buffer_size(&stream->istream);
i_assert(max_size > 0);
if (stream->buffer_size > max_size)
stream->buffer_size = max_size;
if (stream->buffer_size <= old_size)
stream->buffer_size = old_size;
else
i_stream_w_buffer_realloc(stream, old_size);
}
bool i_stream_try_alloc(struct istream_private *stream,
size_t wanted_size, size_t *size_r)
{
i_assert(wanted_size > 0);
if (wanted_size > stream->buffer_size - stream->pos) {
if (stream->skip > 0) {
/* remove the unused bytes from beginning of buffer */
if (stream->memarea != NULL &&
memarea_get_refcount(stream->memarea) > 1) {
/* The memarea is still referenced. We can't
overwrite data until extra references are
gone. */
i_stream_w_buffer_realloc(stream, stream->buffer_size);
}
i_stream_compress(stream);
} else if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream)) {
/* buffer is full - grow it */
i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
}
}
*size_r = stream->buffer_size - stream->pos;
if (stream->try_alloc_limit > 0 &&
*size_r > stream->try_alloc_limit)
*size_r = stream->try_alloc_limit;
return *size_r > 0;
}
bool ATTR_NOWARN_UNUSED_RESULT
i_stream_try_alloc_avoid_compress(struct istream_private *stream,
size_t wanted_size, size_t *size_r)
{
size_t old_skip = stream->skip;
/* try first with skip=0, so no compression is done */
stream->skip = 0;
bool ret = i_stream_try_alloc(stream, wanted_size, size_r);
stream->skip = old_skip;
if (ret || old_skip == 0)
return ret;
/* it's full. try with compression. */
return i_stream_try_alloc(stream, wanted_size, size_r);
}
void *i_stream_alloc(struct istream_private *stream, size_t size)
{
size_t old_size, avail_size;
i_stream_try_alloc(stream, size, &avail_size);
if (avail_size < size) {
old_size = stream->buffer_size;
stream->buffer_size = nearest_power(stream->pos + size);
i_stream_w_buffer_realloc(stream, old_size);
i_stream_try_alloc(stream, size, &avail_size);
i_assert(avail_size >= size);
}
return stream->w_buffer + stream->pos;
}
bool i_stream_add_data(struct istream *_stream, const unsigned char *data,
size_t size)
{
struct istream_private *stream = _stream->real_stream;
size_t size2;
i_stream_try_alloc(stream, size, &size2);
if (size > size2)
return FALSE;
memcpy(stream->w_buffer + stream->pos, data, size);
stream->pos += size;
return TRUE;
}
void i_stream_set_input_pending(struct istream *stream, bool pending)
{
if (!pending)
return;
while (stream->real_stream->parent != NULL) {
i_assert(stream->real_stream->io == NULL);
stream = stream->real_stream->parent;
}
if (stream->real_stream->io != NULL)
io_set_pending(stream->real_stream->io);
}
void i_stream_switch_ioloop(struct istream *stream)
{
do {
if (stream->real_stream->switch_ioloop != NULL)
stream->real_stream->switch_ioloop(stream->real_stream);
stream = stream->real_stream->parent;
} while (stream != NULL);
}
void i_stream_set_io(struct istream *stream, struct io *io)
{
while (stream->real_stream->parent != NULL) {
i_assert(stream->real_stream->io == NULL);
stream = stream->real_stream->parent;
}
i_assert(stream->real_stream->io == NULL);
stream->real_stream->io = io;
}
void i_stream_unset_io(struct istream *stream, struct io *io)
{
while (stream->real_stream->parent != NULL) {
i_assert(stream->real_stream->io == NULL);
stream = stream->real_stream->parent;
}
i_assert(stream->real_stream->io == io);
stream->real_stream->io = NULL;
}
static void
i_stream_default_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
struct istream_private *_stream = (struct istream_private *)stream;
_stream->max_buffer_size = max_size;
if (_stream->parent != NULL)
i_stream_set_max_buffer_size(_stream->parent, max_size);
}
static void i_stream_default_close(struct iostream_private *stream,
bool close_parent)
{
struct istream_private *_stream = (struct istream_private *)stream;
if (close_parent)
i_stream_close(_stream->parent);
}
static void i_stream_default_destroy(struct iostream_private *stream)
{
struct istream_private *_stream = (struct istream_private *)stream;
i_stream_free_buffer(_stream);
i_stream_unref(&_stream->parent);
}
static void
i_stream_default_seek_seekable(struct istream_private *stream,
uoff_t v_offset, bool mark ATTR_UNUSED)
{
stream->istream.v_offset = v_offset;
stream->skip = stream->pos = 0;
}
void i_stream_default_seek_nonseekable(struct istream_private *stream,
uoff_t v_offset, bool mark ATTR_UNUSED)
{
size_t available;
if (stream->istream.v_offset > v_offset)
i_panic("stream %s doesn't support seeking backwards",
i_stream_get_name(&stream->istream));
while (stream->istream.v_offset < v_offset) {
(void)i_stream_read(&stream->istream);
available = stream->pos - stream->skip;
if (available == 0) {
if (stream->istream.stream_errno != 0) {
/* read failed */
return;
}
io_stream_set_error(&stream->iostream,
"Can't seek to offset %"PRIuUOFF_T
", because we have data only up to offset %"
PRIuUOFF_T" (eof=%d)", v_offset,
stream->istream.v_offset, stream->istream.eof ? 1 : 0);
stream->istream.stream_errno = ESPIPE;
return;
}
if (available <= v_offset - stream->istream.v_offset)
i_stream_skip(&stream->istream, available);
else {
i_stream_skip(&stream->istream,
v_offset - stream->istream.v_offset);
}
}
}
static int
i_stream_default_stat(struct istream_private *stream, bool exact)
{
const struct stat *st;
if (stream->parent == NULL)
return stream->istream.stream_errno == 0 ? 0 : -1;
if (i_stream_stat(stream->parent, exact, &st) < 0) {
stream->istream.stream_errno = stream->parent->stream_errno;
return -1;
}
stream->statbuf = *st;
if (exact && !stream->stream_size_passthrough) {
/* exact size is not known, even if parent returned something */
stream->statbuf.st_size = -1;
}
return 0;
}
static int
i_stream_default_get_size(struct istream_private *stream,
bool exact, uoff_t *size_r)
{
if (stream->stat(stream, exact) < 0)
return -1;
if (stream->statbuf.st_size == -1)
return 0;
*size_r = stream->statbuf.st_size;
return 1;
}
void i_stream_init_parent(struct istream_private *_stream,
struct istream *parent)
{
_stream->access_counter = parent->real_stream->access_counter;
_stream->parent = parent;
_stream->parent_start_offset = parent->v_offset;
_stream->parent_expected_offset = parent->v_offset;
_stream->start_offset = parent->v_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,
enum istream_create_flag flags)
{
bool noop_snapshot = (flags & ISTREAM_CREATE_FLAG_NOOP_SNAPSHOT) != 0;
_stream->fd = fd;
if (parent != NULL)
i_stream_init_parent(_stream, parent);
else if (_stream->memarea == NULL && !noop_snapshot) {
/* The stream has no parent and no memarea yet. We'll assume
that it wants to be using memareas for the reads. */
_stream->memarea = memarea_init_empty();
}
_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->snapshot == NULL) {
_stream->snapshot = noop_snapshot ?
i_stream_noop_snapshot :
i_stream_default_snapshot;
}
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;
i_zero(&_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);
if (_stream->istream.stream_errno != 0)
_stream->istream.eof = TRUE;
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, 0);
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;
}