bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "ioloop.h"
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#include "array.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "str.h"
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen#include "memarea.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "istream-private.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream);
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen i_free(stream->real_stream->iostream.name);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen}
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenconst char *i_stream_get_name(struct istream *stream)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen while (stream->real_stream->iostream.name == NULL) {
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen stream = stream->real_stream->parent;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen if (stream == NULL)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen return "";
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen }
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen return stream->real_stream->iostream.name;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen}
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen stream->closed = TRUE;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if (stream->stream_errno == 0)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen stream->stream_errno = EPIPE;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenvoid i_stream_destroy(struct istream **stream)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen{
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek if (*stream == NULL)
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek return;
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_stream_close_full(*stream, FALSE);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_stream_unref(stream);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_ref(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid i_stream_unref(struct istream **stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek struct istream_private *_stream;
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek if (*stream == NULL)
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek return;
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek _stream = (*stream)->real_stream;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
f4169072aebf5607b272f954fb405c838e1aa4d6Josef 'Jeff' Sipek if (!io_stream_unref(&_stream->iostream)) {
e9fbe5e18b798728041b7e2ffc6c4fa964fc35a3Josef 'Jeff' Sipek str_free(&_stream->line_str);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen i_stream_snapshot_free(&_stream->prev_snapshot);
f4169072aebf5607b272f954fb405c838e1aa4d6Josef 'Jeff' Sipek i_stream_unref(&_stream->parent);
f4169072aebf5607b272f954fb405c838e1aa4d6Josef 'Jeff' Sipek io_stream_free(&_stream->iostream);
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *stream = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#undef i_stream_add_destroy_callback
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen istream_callback_t *callback, void *context)
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen{
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen callback, context);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen}
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen void (*callback)())
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen{
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen callback);
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen}
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenint i_stream_get_fd(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->fd;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenconst char *i_stream_get_error(struct istream *stream)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen struct istream *s;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen /* we'll only return errors for streams that have stream_errno set or
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen that have reached EOF. we might be returning unintended error
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen otherwise. */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (stream->stream_errno == 0)
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen return stream->eof ? "EOF" : "<no error>";
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (s->stream_errno == 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen break;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (s->real_stream->iostream.error != NULL)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return s->real_stream->iostream.error;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return strerror(stream->stream_errno);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainenconst char *i_stream_get_disconnect_reason(struct istream *stream)
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen{
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen return io_stream_get_disconnect_reason(stream, NULL);
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen}
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_close(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
660ecbaf80e6b3cf3a70ed1e0cdf7f8af6d895d0Josef 'Jeff' Sipek if (stream != NULL)
660ecbaf80e6b3cf3a70ed1e0cdf7f8af6d895d0Josef 'Jeff' Sipek i_stream_close_full(stream, TRUE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen{
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen stream->real_stream->init_buffer_size = size;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen}
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen{
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen size_t max_size = 0;
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen do {
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen if (max_size < stream->real_stream->max_buffer_size)
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen max_size = stream->real_stream->max_buffer_size;
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen stream = stream->real_stream->parent;
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen } while (stream != NULL);
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen return max_size;
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen}
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen stream->real_stream->return_nolf_line = set;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainenvoid i_stream_set_persistent_buffers(struct istream *stream, bool set)
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen{
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen do {
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen stream->real_stream->nonpersistent_buffers = !set;
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen stream = stream->real_stream->parent;
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen } while (stream != NULL);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen}
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainenvoid i_stream_set_blocking(struct istream *stream, bool blocking)
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen{
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen int prev_fd = -1;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen do {
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen stream->blocking = blocking;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen if (stream->real_stream->fd != -1 &&
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen stream->real_stream->fd != prev_fd) {
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen fd_set_nonblock(stream->real_stream->fd, !blocking);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen prev_fd = stream->real_stream->fd;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen }
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen stream = stream->real_stream->parent;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen } while (stream != NULL);
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen}
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (stream->parent == NULL)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream->access_counter++;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen else {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream->access_counter =
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream->parent->real_stream->access_counter;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainenstatic bool snapshot_has_memarea(struct istream_snapshot *snapshot,
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen struct memarea *memarea)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen{
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (snapshot->old_memarea == memarea)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return TRUE;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (snapshot->prev_snapshot != NULL)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return snapshot_has_memarea(snapshot->prev_snapshot, memarea);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return FALSE;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen}
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainenstruct istream_snapshot *
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Siraineni_stream_default_snapshot(struct istream_private *stream,
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen struct istream_snapshot *prev_snapshot)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen{
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen struct istream_snapshot *snapshot;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (stream->memarea != NULL) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (prev_snapshot != NULL) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (snapshot_has_memarea(prev_snapshot, stream->memarea))
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return prev_snapshot;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen /* This stream has a memarea. Reference it, so we can later on
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen rollback if needed. */
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen snapshot = i_new(struct istream_snapshot, 1);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen snapshot->old_memarea = stream->memarea;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen snapshot->prev_snapshot = prev_snapshot;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen memarea_ref(snapshot->old_memarea);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return snapshot;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (stream->parent == NULL) {
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen if (stream->nonpersistent_buffers) {
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen /* Assume that memarea would be used normally, but
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen now it's NULL because the buffer is empty and
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen empty buffers are freed. */
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen i_assert(stream->skip == stream->pos);
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen return prev_snapshot;
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen i_panic("%s is missing istream.snapshot() implementation",
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen i_stream_get_name(&stream->istream));
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen struct istream_private *_parent_stream =
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen stream->parent->real_stream;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return _parent_stream->snapshot(_parent_stream, prev_snapshot);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen}
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainenvoid i_stream_snapshot_free(struct istream_snapshot **_snapshot)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen{
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen struct istream_snapshot *snapshot = *_snapshot;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (*_snapshot == NULL)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen *_snapshot = NULL;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen i_stream_snapshot_free(&snapshot->prev_snapshot);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (snapshot->old_memarea != NULL)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen memarea_unref(&snapshot->old_memarea);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen i_free(snapshot);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen}
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainenstatic struct istream_snapshot *
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Siraineni_stream_noop_snapshot(struct istream_private *stream ATTR_UNUSED,
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen struct istream_snapshot *prev_snapshot)
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen{
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen return prev_snapshot;
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen}
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenssize_t i_stream_read(struct istream *stream)
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen{
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen struct istream_private *_stream = stream->real_stream;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen ssize_t ret;
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen#ifdef DEBUG
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen unsigned char prev_buf[4];
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen const unsigned char *prev_data = _stream->buffer;
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen size_t prev_skip = _stream->skip, prev_pos = _stream->pos;
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen bool invalid = i_stream_is_buffer_invalid(_stream);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen i_assert(prev_skip <= prev_pos);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen if (invalid)
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen ;
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen else if (prev_pos - prev_skip <= 4)
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen memcpy(prev_buf, prev_data + prev_skip, prev_pos - prev_skip);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen else {
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen memcpy(prev_buf, prev_data + prev_skip, 2);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen memcpy(prev_buf+2, prev_data + prev_pos - 2, 2);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen }
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen#endif
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen _stream->prev_snapshot =
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen _stream->snapshot(_stream, _stream->prev_snapshot);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen ret = i_stream_read_memarea(stream);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen if (ret > 0)
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen i_stream_snapshot_free(&_stream->prev_snapshot);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen#ifdef DEBUG
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen else if (!invalid) {
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen i_assert((_stream->pos - _stream->skip) == (prev_pos - prev_skip));
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen if (prev_pos - prev_skip <= 4)
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen i_assert(memcmp(prev_buf, prev_data + prev_skip, prev_pos - prev_skip) == 0);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen else {
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen i_assert(memcmp(prev_buf, prev_data + prev_skip, 2) == 0);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen i_assert(memcmp(prev_buf+2, prev_data + prev_pos - 2, 2) == 0);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen }
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen }
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen#endif
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen return ret;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen}
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainenssize_t i_stream_read_memarea(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen size_t old_size;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen ssize_t ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
a2738cdb6d2733fb3e186331d68009421a19ea00Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen stream->eof = TRUE;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen stream->eof = FALSE;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (_stream->parent != NULL)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen old_size = _stream->pos - _stream->skip;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen ret = _stream->read(_stream);
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen switch (ret) {
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen case -2:
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen i_assert(_stream->skip != _stream->pos);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen break;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen case -1:
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (stream->stream_errno != 0) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* error handling should be easier if we now just
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen assume the stream is now at EOF */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen stream->eof = TRUE;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen } else {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_assert(stream->eof);
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen break;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen case 0:
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen i_assert(!stream->blocking);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen break;
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen default:
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen i_assert(ret > 0);
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen i_assert(_stream->skip < _stream->pos);
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen _stream->last_read_timeval = ioloop_timeval;
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen break;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen if (stream->stream_errno != 0) {
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen /* error handling should be easier if we now just
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen assume the stream is now at EOF. Note that we could get here
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen even if read() didn't return -1, although that's a little
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen bit sloppy istream implementation. */
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen stream->eof = TRUE;
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen }
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_update(_stream);
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen /* verify that parents' access_counters are valid. the parent's
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen i_stream_read() should guarantee this. */
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen i_assert(!i_stream_is_buffer_invalid(_stream));
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainenint i_stream_read_more_memarea(struct istream *stream,
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen const unsigned char **data_r, size_t *size_r)
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen{
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen *data_r = i_stream_get_data(stream, size_r);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen if (*size_r > 0)
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen return 1;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen int ret = i_stream_read_memarea(stream);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen *data_r = i_stream_get_data(stream, size_r);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen return ret;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen}
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainenvoid i_stream_get_last_read_time(struct istream *stream, struct timeval *tv_r)
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen{
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen *tv_r = stream->real_stream->last_read_timeval;
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen}
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct istream_private *stream = istream->real_stream;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen size_t pos;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen ssize_t ret;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->pos -= stream->skip;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->skip = 0;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (pos > stream->pos)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen ret = 0;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen else do {
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen if ((ret = i_stream_read_memarea(stream->parent)) == -2) {
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen i_stream_update(stream);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return -2;
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->istream.eof = stream->parent->eof;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* check again, in case the parent stream had been seeked
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen backwards and the previous read() didn't get us far
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen enough. */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen } while (pos <= stream->pos && ret > 0);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen (ret == 0 ? 0 : -1);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->pos = pos;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_assert(ret != -1 || stream->istream.eof ||
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->istream.stream_errno != 0);
c6b6ac7819931dfa92c0182ffaa7db07ac6ab0daTimo Sirainen i_stream_update(stream);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return ret;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainenvoid i_stream_free_buffer(struct istream_private *stream)
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen{
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen if (stream->memarea != NULL) {
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen memarea_unref(&stream->memarea);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen stream->w_buffer = NULL;
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen } else if (stream->w_buffer != NULL) {
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen i_free_and_null(stream->w_buffer);
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen } else {
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen /* don't know how to free it */
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen return;
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen }
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen stream->buffer_size = 0;
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen}
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t data_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen data_size = _stream->pos - _stream->skip;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen if (count <= data_size) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* within buffer */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->v_offset += count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->skip += count;
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen if (_stream->nonpersistent_buffers &&
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen _stream->skip == _stream->pos) {
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen _stream->skip = _stream->pos = 0;
54bd0fec0be357266e299466a582f3c9269884e9Timo Sirainen i_stream_free_buffer(_stream);
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* have to seek forward */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen count -= data_size;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen _stream->skip = _stream->pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->v_offset += data_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi if (unlikely(stream->closed || stream->stream_errno != 0))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (stream->parent == NULL)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return TRUE;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (stream->access_counter !=
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream->parent->real_stream->access_counter)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return FALSE;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen}
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (v_offset >= stream->v_offset &&
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_can_optimize_seek(_stream))
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen else {
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi if (unlikely(stream->closed || stream->stream_errno != 0)) {
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi stream->eof = TRUE;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return;
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream->eof = FALSE;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen _stream->seek(_stream, v_offset, FALSE);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_update(_stream);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen}
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi if (unlikely(stream->closed || stream->stream_errno != 0))
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen stream->eof = FALSE;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, v_offset, TRUE);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_update(_stream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenvoid i_stream_sync(struct istream *stream)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi if (unlikely(stream->closed || stream->stream_errno != 0))
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen return;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (_stream->sync != NULL) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->sync(_stream);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_update(_stream);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi if (unlikely(stream->closed || stream->stream_errno != 0))
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi if (_stream->stat(_stream, exact) < 0) {
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi stream->eof = TRUE;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen *st_r = &_stream->statbuf;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen{
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen struct istream_private *_stream = stream->real_stream;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi if (unlikely(stream->closed || stream->stream_errno != 0))
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return -1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi int ret;
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi if ((ret = _stream->get_size(_stream, exact, size_r)) < 0)
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi stream->eof = TRUE;
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi return ret;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen}
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen{
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen return i_stream_get_data_size(stream) > 0 || !stream->eof;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen}
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
1bc075e2e4ed422f9590c95c3ae223422b97ce6aTimo Sirainenbool i_stream_read_eof(struct istream *stream)
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen{
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen if (i_stream_get_data_size(stream) == 0)
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen (void)i_stream_read(stream);
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen return !i_stream_have_bytes_left(stream);
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen}
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen{
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen uoff_t abs_offset = stream->v_offset;
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen while (stream != NULL) {
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen abs_offset += stream->real_stream->start_offset;
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen stream = stream->real_stream->parent;
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen }
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen return abs_offset;
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen}
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen char *ret;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen size_t end;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen if (i > 0 && stream->buffer[i-1] == '\r') {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end = i - 1;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen stream->line_crlf = TRUE;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen } else {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end = i;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen stream->line_crlf = FALSE;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e6bc5e739360377c5badf0da24208f4836722eaeStephan Bosch if (stream->buffer == stream->w_buffer) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* modify the buffer directly */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->w_buffer[end] = '\0';
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen } else {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* use a temporary string to return it */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (stream->line_str == NULL)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->line_str = str_new(default_pool, 256);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen str_truncate(stream->line_str, 0);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end - stream->skip);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen ret = str_c_modifiable(stream->line_str);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (i < stream->pos)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen i++;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->istream.v_offset += i - stream->skip;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->skip = i;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen return ret;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen _stream->return_nolf_line) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* the last line is missing LF and we want to return it. */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return NULL;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenchar *i_stream_next_line(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen const unsigned char *pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7a77b948806106b46a33f3e6a3869657f49877fdTimo Sirainen if (_stream->skip >= _stream->pos)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen _stream->pos - _stream->skip);
b7651d283ca261015ef3c445f1f27f340f0864e2Timo Sirainen if (pos != NULL) {
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen return i_stream_next_line_finish(_stream,
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen pos - _stream->buffer);
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen } else {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_last_line(_stream);
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenchar *i_stream_read_next_line(struct istream *stream)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen{
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen char *line;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen for (;;) {
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen line = i_stream_next_line(stream);
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen if (line != NULL)
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen break;
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen switch (i_stream_read(stream)) {
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen case -2:
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen io_stream_set_error(&stream->real_stream->iostream,
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen "Line is too long (over %"PRIuSIZE_T
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen " bytes at offset %"PRIuUOFF_T")",
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen i_stream_get_data_size(stream), stream->v_offset);
f20e7fbdc9bdbe8fecb9c661c9b8175f3bb78c69Timo Sirainen stream->stream_errno = errno = ENOBUFS;
c0b1543512bc3e0a3a9f526056a3678a07ce32f5Timo Sirainen stream->eof = TRUE;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen return NULL;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen case -1:
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_last_line(stream->real_stream);
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen case 0:
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen return NULL;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen }
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return line;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen}
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen{
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen return stream->real_stream->line_crlf;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen}
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen{
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (stream->parent == NULL) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* the buffer can't point to parent, because it doesn't exist */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen return FALSE;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (stream->w_buffer != NULL) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* we can pretty safely assume that the stream is using its
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen own private buffer, so it can never become invalid. */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen return FALSE;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (stream->access_counter !=
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen stream->parent->real_stream->access_counter) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* parent has been modified behind this stream, we can't trust
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen that our buffer is valid */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen return TRUE;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen return i_stream_is_buffer_invalid(stream->parent->real_stream);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen}
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenconst unsigned char *
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Siraineni_stream_get_data(struct istream *stream, size_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = 0;
5965eaa2d972e6264cecaf54091cd43019bc7d1fTimo Sirainen return uchar_empty_ptr;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (i_stream_is_buffer_invalid(_stream)) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* This stream may be using parent's buffer directly as
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen _stream->buffer, but the parent stream has already been
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen modified indirectly. This means that the buffer might no
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen longer point to where we assume it points to. So we'll
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen just return the stream as empty until it's read again.
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen It's a bit ugly to suddenly drop data from the stream that
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen was already read, but since this happens only with shared
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen parent istreams the caller is hopefully aware enough that
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen something like this might happen. The other solutions would
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen be to a) try to automatically read the data back (but we
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen can't handle errors..) or b) always copy data to stream's
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen own buffer instead of pointing to parent's buffer (but this
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen causes data copying that is nearly always unnecessary). */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen *size_r = 0;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen /* if we had already read until EOF, mark the stream again as
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen not being at the end of file. */
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen if (stream->stream_errno == 0) {
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen _stream->skip = _stream->pos = 0;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen stream->eof = FALSE;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen }
5965eaa2d972e6264cecaf54091cd43019bc7d1fTimo Sirainen return uchar_empty_ptr;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = _stream->pos - _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->buffer + _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainensize_t i_stream_get_data_size(struct istream *stream)
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen{
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen size_t size;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen (void)i_stream_get_data(stream, &size);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen return size;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen}
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen size_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = _stream->pos - _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->w_buffer + _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen size_t *size_r, size_t threshold)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ssize_t ret = 0;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool read_more = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen do {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (*size_r > threshold)
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen return 1;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we need more data */
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen ret = i_stream_read(stream);
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen if (ret > 0)
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen read_more = TRUE;
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen } while (ret > 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (ret == -2)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return -2;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen if (ret == 0) {
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen /* need to read more */
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen i_assert(!stream->blocking);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return 0;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (stream->eof) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (read_more) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* we read at least some new data */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return 0;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen } else {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_assert(stream->stream_errno != 0);
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen }
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen{
fa39c427573ada77265b833db687ca7e854794a1Timo Sirainen i_assert(stream->memarea == NULL ||
fa39c427573ada77265b833db687ca7e854794a1Timo Sirainen memarea_get_refcount(stream->memarea) == 1);
fa39c427573ada77265b833db687ca7e854794a1Timo Sirainen
6d404348751c19ac37cfb42375abdd3c5f298e30Timo Sirainen if (stream->skip != stream->pos) {
6d404348751c19ac37cfb42375abdd3c5f298e30Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
6d404348751c19ac37cfb42375abdd3c5f298e30Timo Sirainen stream->pos - stream->skip);
6d404348751c19ac37cfb42375abdd3c5f298e30Timo Sirainen }
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->pos -= stream->skip;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->skip = 0;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen}
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainenstatic void i_stream_w_buffer_free(void *buf)
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen{
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen i_free(buf);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen}
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainenstatic void
5ca745ae8e9903ef5265360e4c882e9314595020Timo Siraineni_stream_w_buffer_realloc(struct istream_private *stream, size_t old_size)
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen{
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen void *new_buffer;
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen if (stream->memarea != NULL &&
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen memarea_get_refcount(stream->memarea) == 1) {
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen /* Nobody else is referencing the memarea.
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen We can just reallocate it. */
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen memarea_free_without_callback(&stream->memarea);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen new_buffer = i_realloc(stream->w_buffer, old_size,
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen stream->buffer_size);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen } else {
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen new_buffer = i_malloc(stream->buffer_size);
5aa1aa87a24ff39d566a3ad90d0f8d054118cfe7Timo Sirainen if (old_size > 0) {
5aa1aa87a24ff39d566a3ad90d0f8d054118cfe7Timo Sirainen i_assert(stream->w_buffer != NULL);
5aa1aa87a24ff39d566a3ad90d0f8d054118cfe7Timo Sirainen memcpy(new_buffer, stream->w_buffer, old_size);
5aa1aa87a24ff39d566a3ad90d0f8d054118cfe7Timo Sirainen }
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen if (stream->memarea != NULL)
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen memarea_unref(&stream->memarea);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen }
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen stream->w_buffer = new_buffer;
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen stream->buffer = new_buffer;
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen stream->memarea = memarea_init(stream->w_buffer, stream->buffer_size,
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen i_stream_w_buffer_free, new_buffer);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen}
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen size_t old_size, max_size;
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen old_size = stream->buffer_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = stream->pos + bytes;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen stream->buffer_size = stream->init_buffer_size;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen else
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen max_size = i_stream_get_max_buffer_size(&stream->istream);
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen i_assert(max_size > 0);
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen if (stream->buffer_size > max_size)
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen stream->buffer_size = max_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen if (stream->buffer_size <= old_size)
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen stream->buffer_size = old_size;
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen else
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen i_stream_w_buffer_realloc(stream, old_size);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen size_t wanted_size, size_t *size_r)
14175321ddb88619015866978c05a27786ca4814Timo Sirainen{
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_assert(wanted_size > 0);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen if (stream->skip > 0) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* remove the unused bytes from beginning of buffer */
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen if (stream->memarea != NULL &&
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen memarea_get_refcount(stream->memarea) > 1) {
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen /* The memarea is still referenced. We can't
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen overwrite data until extra references are
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen gone. */
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen i_stream_w_buffer_realloc(stream, stream->buffer_size);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen }
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen i_stream_compress(stream);
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen } else if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream)) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* buffer is full - grow it */
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen }
14175321ddb88619015866978c05a27786ca4814Timo Sirainen }
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *size_r = stream->buffer_size - stream->pos;
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen if (stream->try_alloc_limit > 0 &&
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen *size_r > stream->try_alloc_limit)
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen *size_r = stream->try_alloc_limit;
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen return *size_r > 0;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen}
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainenbool ATTR_NOWARN_UNUSED_RESULT
51d379cbc50242a13462d0fded50e013eb00cc07Timo Siraineni_stream_try_alloc_avoid_compress(struct istream_private *stream,
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen size_t wanted_size, size_t *size_r)
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen{
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen size_t old_skip = stream->skip;
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen /* try first with skip=0, so no compression is done */
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen stream->skip = 0;
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen bool ret = i_stream_try_alloc(stream, wanted_size, size_r);
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen stream->skip = old_skip;
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen if (ret || old_skip == 0)
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen return ret;
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen /* it's full. try with compression. */
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen return i_stream_try_alloc(stream, wanted_size, size_r);
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen}
51d379cbc50242a13462d0fded50e013eb00cc07Timo Sirainen
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen{
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen size_t old_size, avail_size;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen if (avail_size < size) {
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen old_size = stream->buffer_size;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen i_stream_w_buffer_realloc(stream, old_size);
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen i_assert(avail_size >= size);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen }
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen return stream->w_buffer + stream->pos;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen}
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen size_t size)
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen{
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen struct istream_private *stream = _stream->real_stream;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen size_t size2;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen i_stream_try_alloc(stream, size, &size2);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen if (size > size2)
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen return FALSE;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen stream->pos += size;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen return TRUE;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen}
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainenstruct istream *i_stream_get_root_io(struct istream *stream)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen{
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen while (stream->real_stream->parent != NULL) {
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen i_assert(stream->real_stream->io == NULL);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen stream = stream->real_stream->parent;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen }
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen return stream;
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen}
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen{
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen if (!pending)
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen return;
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen stream = i_stream_get_root_io(stream);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (stream->real_stream->io != NULL)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen io_set_pending(stream->real_stream->io);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen}
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
038c2831447440bf0bef89b43dd0968afc298abcStephan Boschvoid i_stream_switch_ioloop_to(struct istream *stream, struct ioloop *ioloop)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen{
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch io_stream_switch_ioloop_to(&stream->real_stream->iostream, ioloop);
b3b813a6473d1210eee94bd60eaa6bafd2131ed3Stephan Bosch
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen do {
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch if (stream->real_stream->switch_ioloop_to != NULL) {
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch stream->real_stream->switch_ioloop_to(
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch stream->real_stream, ioloop);
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch }
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen stream = stream->real_stream->parent;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen } while (stream != NULL);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen}
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
038c2831447440bf0bef89b43dd0968afc298abcStephan Boschvoid i_stream_switch_ioloop(struct istream *stream)
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch{
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch i_stream_switch_ioloop_to(stream, current_ioloop);
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch}
038c2831447440bf0bef89b43dd0968afc298abcStephan Bosch
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_set_io(struct istream *stream, struct io *io)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen{
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen stream = i_stream_get_root_io(stream);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen i_assert(stream->real_stream->io == NULL);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen stream->real_stream->io = io;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen}
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_unset_io(struct istream *stream, struct io *io)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen{
5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275Timo Sirainen stream = i_stream_get_root_io(stream);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen i_assert(stream->real_stream->io == io);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen stream->real_stream->io = NULL;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen}
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen size_t max_size)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen _stream->max_buffer_size = max_size;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen if (_stream->parent != NULL)
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen}
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void i_stream_default_close(struct iostream_private *stream,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen bool close_parent)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek if (close_parent)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_stream_close(_stream->parent);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen{
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen
54bd0fec0be357266e299466a582f3c9269884e9Timo Sirainen i_stream_free_buffer(_stream);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&_stream->parent);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainenstatic void
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Siraineni_stream_default_seek_seekable(struct istream_private *stream,
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen{
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen stream->istream.v_offset = v_offset;
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen stream->skip = stream->pos = 0;
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen}
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainenvoid i_stream_default_seek_nonseekable(struct istream_private *stream,
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen{
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen size_t available;
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen if (stream->istream.v_offset > v_offset)
66d84e6f0ae34a3cf5b8fa8e009d6caf025b6a2aTimo Sirainen i_panic("stream %s doesn't support seeking backwards",
66d84e6f0ae34a3cf5b8fa8e009d6caf025b6a2aTimo Sirainen i_stream_get_name(&stream->istream));
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen while (stream->istream.v_offset < v_offset) {
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen (void)i_stream_read(&stream->istream);
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen available = stream->pos - stream->skip;
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen if (available == 0) {
b80c329a25b5b07f5e68cd44ef0fef9db6613486Timo Sirainen if (stream->istream.stream_errno != 0) {
b80c329a25b5b07f5e68cd44ef0fef9db6613486Timo Sirainen /* read failed */
b80c329a25b5b07f5e68cd44ef0fef9db6613486Timo Sirainen return;
b80c329a25b5b07f5e68cd44ef0fef9db6613486Timo Sirainen }
73b9c241e7fb6abdccda88e88fbd32e844dbc185Timo Sirainen io_stream_set_error(&stream->iostream,
73b9c241e7fb6abdccda88e88fbd32e844dbc185Timo Sirainen "Can't seek to offset %"PRIuUOFF_T
73b9c241e7fb6abdccda88e88fbd32e844dbc185Timo Sirainen ", because we have data only up to offset %"
73b9c241e7fb6abdccda88e88fbd32e844dbc185Timo Sirainen PRIuUOFF_T" (eof=%d)", v_offset,
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen stream->istream.v_offset, stream->istream.eof ? 1 : 0);
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen stream->istream.stream_errno = ESPIPE;
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen return;
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen }
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen if (available <= v_offset - stream->istream.v_offset)
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen i_stream_skip(&stream->istream, available);
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen else {
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen i_stream_skip(&stream->istream,
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen v_offset - stream->istream.v_offset);
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen }
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen }
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen}
d9ab8a13b51c9d8f4e13e1bf785eeadce6702b3bTimo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenstatic int
5df8396a7cbad0b38b83a86667fb3d4c223f6f7cTimo Siraineni_stream_default_stat(struct istream_private *stream, bool exact)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen const struct stat *st;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
5df8396a7cbad0b38b83a86667fb3d4c223f6f7cTimo Sirainen if (stream->parent == NULL)
d5b3f66491101aba8667369586c95c615cb26ae6Timo Sirainen return stream->istream.stream_errno == 0 ? 0 : -1;
5df8396a7cbad0b38b83a86667fb3d4c223f6f7cTimo Sirainen
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen stream->statbuf = *st;
9db5ade1c16c7f67c51004f28c28ea335755d3f0Timo Sirainen if (exact && !stream->stream_size_passthrough) {
9db5ade1c16c7f67c51004f28c28ea335755d3f0Timo Sirainen /* exact size is not known, even if parent returned something */
9db5ade1c16c7f67c51004f28c28ea335755d3f0Timo Sirainen stream->statbuf.st_size = -1;
9db5ade1c16c7f67c51004f28c28ea335755d3f0Timo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return 0;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenstatic int
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Siraineni_stream_default_get_size(struct istream_private *stream,
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen bool exact, uoff_t *size_r)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen{
6eb0192085073a63ea03443860c412bb5312dd7eTimo Sirainen if (stream->stat(stream, exact) < 0)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return -1;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (stream->statbuf.st_size == -1)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return 0;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen *size_r = stream->statbuf.st_size;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return 1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen}
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainenvoid i_stream_init_parent(struct istream_private *_stream,
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen struct istream *parent)
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen{
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->access_counter = parent->real_stream->access_counter;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->parent = parent;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->parent_start_offset = parent->v_offset;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->parent_expected_offset = parent->v_offset;
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen _stream->start_offset = parent->v_offset;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen /* if parent stream is an istream-error, copy the error */
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->istream.stream_errno = parent->stream_errno;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->istream.eof = parent->eof;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen i_stream_ref(parent);
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen}
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainenstruct istream *
2974dca6be5120e49279f06c8aa952e5fac56048Timo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd,
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen enum istream_create_flag flags)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen bool noop_snapshot = (flags & ISTREAM_CREATE_FLAG_NOOP_SNAPSHOT) != 0;
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->fd = fd;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen if (parent != NULL)
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen i_stream_init_parent(_stream, parent);
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen else if (_stream->memarea == NULL && !noop_snapshot) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen /* The stream has no parent and no memarea yet. We'll assume
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen that it wants to be using memareas for the reads. */
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen _stream->memarea = memarea_init_empty();
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->istream.real_stream = _stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if (_stream->iostream.close == NULL)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen _stream->iostream.close = i_stream_default_close;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen if (_stream->iostream.destroy == NULL)
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen _stream->iostream.destroy = i_stream_default_destroy;
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen if (_stream->seek == NULL) {
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen _stream->seek = _stream->istream.seekable ?
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen i_stream_default_seek_seekable :
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen i_stream_default_seek_nonseekable;
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (_stream->stat == NULL)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen _stream->stat = i_stream_default_stat;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (_stream->get_size == NULL)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen _stream->get_size = i_stream_default_get_size;
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen if (_stream->snapshot == NULL) {
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen _stream->snapshot = noop_snapshot ?
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen i_stream_noop_snapshot :
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen i_stream_default_snapshot;
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen _stream->iostream.set_max_buffer_size =
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_stream_default_set_max_buffer_size;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (_stream->init_buffer_size == 0)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen _stream->init_buffer_size = I_STREAM_MIN_SIZE;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&_stream->statbuf);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_size = -1;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_atime =
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_mtime =
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_ctime = ioloop_time;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_init(&_stream->iostream);
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi if (_stream->istream.stream_errno != 0)
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi _stream->istream.eof = TRUE;
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return &_stream->istream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainenstruct istream *i_stream_create_error(int stream_errno)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen{
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen struct istream_private *stream;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream = i_new(struct istream_private, 1);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream->istream.closed = TRUE;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream->istream.readable_fd = FALSE;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream->istream.blocking = TRUE;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream->istream.seekable = TRUE;
d14e62b7b37dc78fcc940aca25042eceb358b156Timo Sirainen stream->istream.eof = TRUE;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream->istream.stream_errno = stream_errno;
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen i_stream_create(stream, NULL, -1, 0);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen i_stream_set_name(&stream->istream, "(error)");
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen return &stream->istream;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen}
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainenstruct istream *
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Siraineni_stream_create_error_str(int stream_errno, const char *fmt, ...)
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen{
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen struct istream *input;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen va_list args;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen va_start(args, fmt);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen input = i_stream_create_error(stream_errno);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen io_stream_set_verror(&input->real_stream->iostream, fmt, args);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen va_end(args);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen return input;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen}