istream.c revision f20e7fbdc9bdbe8fecb9c661c9b8175f3bb78c69
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2014 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"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "istream-private.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo 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{
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{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (_stream->iostream.refcount == 1) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (_stream->line_str != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str_free(&_stream->line_str);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_unref(&(*stream)->real_stream->iostream);
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{
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen struct iostream_destroy_callback *dc;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (!array_is_created(&iostream->destroy_callbacks))
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_array_init(&iostream->destroy_callbacks, 2);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen dc = array_append_space(&iostream->destroy_callbacks);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen dc->callback = callback;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen dc->context = context;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen}
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen void (*callback)())
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen{
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen const struct iostream_destroy_callback *dcs;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen unsigned int i, count;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen dcs = array_get(&iostream->destroy_callbacks, &count);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen for (i = 0; i < count; i++) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (dcs[i].callback == callback) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen array_delete(&iostream->destroy_callbacks, i, 1);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen }
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen }
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_unreached();
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
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* we'll only return errors for streams that have stream_errno set.
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen we might be returning unintended error otherwise. */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (stream->stream_errno == 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return "<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
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_close(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen 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{
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen return stream->real_stream->max_buffer_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
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
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenssize_t i_stream_read(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)) {
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);
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen break;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_update(_stream);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo 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 {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return -2;
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);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return ret;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo 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;
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
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen stream->stream_errno = 0;
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 {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (unlikely(stream->closed))
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
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
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
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
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
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
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (_stream->stat(_stream, exact) < 0)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
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
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (unlikely(stream->closed))
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return -1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return _stream->get_size(_stream, exact, size_r);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen}
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenbool i_stream_have_bytes_left(const struct istream *stream)
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return !stream->eof || _stream->skip != _stream->pos;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen}
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainenbool i_stream_is_eof(struct istream *stream)
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen{
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen const struct istream_private *_stream = stream->real_stream;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen if (_stream->skip == _stream->pos)
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{
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen return stream->real_stream->abs_start_offset + stream->v_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
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (stream->w_buffer != NULL) {
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
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen if (_stream->skip >= _stream->pos) {
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen if (!unlikely(stream->closed))
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen stream->stream_errno = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen }
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:
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
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenconst unsigned char *
68a4946b12583b88fa802e52ebee45cd96056772Timo Siraineni_stream_get_data(const struct istream *stream, size_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos) {
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->buffer + _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainensize_t i_stream_get_data_size(const struct istream *stream)
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen{
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen const struct istream_private *_stream = stream->real_stream;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen if (_stream->skip >= _stream->pos)
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen return 0;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen else
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen return _stream->pos - _stream->skip;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen}
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenunsigned char *i_stream_get_modifiable_data(const struct istream *stream,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen size_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const 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{
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->pos - stream->skip);
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->pos -= stream->skip;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->skip = 0;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen}
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen size_t old_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen i_assert(stream->max_buffer_size > 0);
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
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen if (stream->buffer_size > stream->max_buffer_size)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = stream->max_buffer_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen if (stream->buffer_size <= old_size)
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen stream->buffer_size = old_size;
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen else {
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen stream->buffer_size);
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen stream->buffer = stream->w_buffer;
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen }
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 */
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_stream_compress(stream);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen } else if (stream->max_buffer_size == 0 ||
14175321ddb88619015866978c05a27786ca4814Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
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
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);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen stream->buffer_size);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen stream->buffer = stream->w_buffer;
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
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen{
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (!pending)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen return;
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 }
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (stream->real_stream->io != NULL)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen io_set_pending(stream->real_stream->io);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen}
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_switch_ioloop(struct istream *stream)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen{
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen do {
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (stream->real_stream->switch_ioloop != NULL)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen stream->real_stream->switch_ioloop(stream->real_stream);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen stream = stream->real_stream->parent;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen } while (stream != NULL);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen}
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_set_io(struct istream *stream, struct io *io)
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 }
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{
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 }
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
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if (close_parent && _stream->parent != NULL)
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
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen i_free(_stream->w_buffer);
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen if (_stream->parent != NULL)
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen 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) {
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
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
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{
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo 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;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->abs_start_offset = parent->v_offset +
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen parent->real_stream->abs_start_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 *
9511a40d933181045343110c8101b75887062aaeTimo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->fd = fd;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen if (parent != NULL)
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen i_stream_init_parent(_stream, parent);
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;
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
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_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);
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;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen i_stream_create(stream, NULL, -1);
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}