istream.c revision 4334b9b032298defd4d3906f5357698ff016ead0
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "istream-internal.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainenvoid i_stream_destroy(struct istream **stream)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_close(*stream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_unref(stream);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainenvoid i_stream_ref(struct istream *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid i_stream_unref(struct istream **stream)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (_stream->iostream.refcount == 1) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (_stream->line_str != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_free(&_stream->line_str);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_stream_unref(&(*stream)->real_stream->iostream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *stream = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#undef i_stream_set_destroy_callback
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_set_destroy_callback(struct istream *stream,
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen istream_callback_t *callback, void *context)
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen{
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen iostream->destroy_callback = callback;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen iostream->destroy_context = context;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint i_stream_get_fd(struct istream *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct istream_private *_stream = stream->real_stream;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return _stream->fd;
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid i_stream_close(struct istream *stream)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io_stream_close(&stream->real_stream->iostream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->closed = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (stream->stream_errno == 0)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen stream->stream_errno = ENOENT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen stream->real_stream->init_buffer_size = size;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen{
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->real_stream->return_nolf_line = set;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen if (stream->parent == NULL)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen stream->access_counter++;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen else {
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen stream->access_counter =
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen stream->parent->real_stream->access_counter;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenssize_t i_stream_read(struct istream *stream)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct istream_private *_stream = stream->real_stream;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen size_t old_size;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen ssize_t ret;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (unlikely(stream->closed))
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return -1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen stream->eof = FALSE;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen stream->stream_errno = 0;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (_stream->parent != NULL)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen old_size = _stream->pos - _stream->skip;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen ret = _stream->read(_stream);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen switch (ret) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen case -2:
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen i_assert(_stream->skip != _stream->pos);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen break;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen case -1:
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (stream->stream_errno != 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* error handling should be easier if we now just
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen assume the stream is now at EOF */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen stream->eof = TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen } else {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_assert(stream->eof);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen break;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen case 0:
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_assert(!stream->blocking);
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen break;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen default:
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_assert(ret > 0);
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen break;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_stream_update(_stream);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return ret;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen struct istream_private *stream = istream->real_stream;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen size_t pos;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ssize_t ret;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen stream->pos -= stream->skip;
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen stream->skip = 0;
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (pos > stream->pos)
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen ret = 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen else do {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if ((ret = i_stream_read(stream->parent)) == -2)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -2;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen stream->istream.eof = stream->parent->eof;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* check again, in case the parent stream had been seeked
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen backwards and the previous read() didn't get us far
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen enough. */
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen } while (pos <= stream->pos && ret > 0);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen (ret == 0 ? 0 : -1);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen stream->pos = pos;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen i_assert(ret != -1 || stream->istream.eof ||
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen stream->istream.stream_errno != 0);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return ret;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen{
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen struct istream_private *_stream = stream->real_stream;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen size_t data_size;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen data_size = _stream->pos - _stream->skip;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (count <= data_size) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* within buffer */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen stream->v_offset += count;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen _stream->skip += count;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* have to seek forward */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen count -= data_size;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen _stream->skip = _stream->pos;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen stream->v_offset += data_size;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (unlikely(stream->closed))
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen stream->stream_errno = 0;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen}
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen{
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen if (stream->parent == NULL)
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen return TRUE;
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (stream->access_counter !=
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen stream->parent->real_stream->access_counter)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return FALSE;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen struct istream_private *_stream = stream->real_stream;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (v_offset >= stream->v_offset &&
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen i_stream_can_optimize_seek(_stream))
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen else {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (unlikely(stream->closed))
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen stream->eof = FALSE;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen _stream->seek(_stream, v_offset, FALSE);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen i_stream_update(_stream);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen struct istream_private *_stream = stream->real_stream;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (unlikely(stream->closed))
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen stream->eof = FALSE;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen _stream->seek(_stream, v_offset, TRUE);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen i_stream_update(_stream);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenvoid i_stream_sync(struct istream *stream)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen struct istream_private *_stream = stream->real_stream;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (unlikely(stream->closed))
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (_stream->sync != NULL) {
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen _stream->sync(_stream);
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen i_stream_update(_stream);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenconst struct stat *i_stream_stat(struct istream *stream, bool exact)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen struct istream_private *_stream = stream->real_stream;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (unlikely(stream->closed))
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return NULL;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return _stream->stat(_stream, exact);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen}
ab286a8b58306eb8d22fc18342b6c199fd428e1eTimo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen{
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen struct istream_private *_stream = stream->real_stream;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (unlikely(stream->closed))
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return -1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return _stream->get_size(_stream, exact, size_r);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenbool i_stream_have_bytes_left(const struct istream *stream)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen const struct istream_private *_stream = stream->real_stream;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return !stream->eof || _stream->skip != _stream->pos;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenbool i_stream_is_eof(struct istream *stream)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen const struct istream_private *_stream = stream->real_stream;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (_stream->skip == _stream->pos)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen (void)i_stream_read(stream);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen return !i_stream_have_bytes_left(stream);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen char *ret;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen size_t end;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r')
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen end = i - 1;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen else
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen end = i;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (stream->w_buffer != NULL) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* modify the buffer directly */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen stream->w_buffer[end] = '\0';
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen } else {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* use a temporary string to return it */
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (stream->line_str == NULL)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen stream->line_str = str_new(default_pool, 256);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen str_truncate(stream->line_str, 0);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen end - stream->skip);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen ret = str_c_modifiable(stream->line_str);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen if (i < stream->pos)
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen i++;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen stream->istream.v_offset += i - stream->skip;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen stream->skip = i;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen return ret;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen}
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen _stream->return_nolf_line) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* the last line is missing LF and we want to return it. */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return NULL;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenchar *i_stream_next_line(struct istream *stream)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen struct istream_private *_stream = stream->real_stream;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen char *ret_buf;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen size_t i;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (_stream->skip >= _stream->pos) {
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen stream->stream_errno = 0;
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen return NULL;
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen }
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen if (unlikely(_stream->w_buffer == NULL)) {
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen i_error("i_stream_next_line() called for unmodifiable stream");
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen return NULL;
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen }
b79ec51bdeef6ef950eb5e890e65cc0491cf5fe9Timo Sirainen
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen /* @UNSAFE */
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen ret_buf = NULL;
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen for (i = _stream->skip; i < _stream->pos; i++) {
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen if (_stream->buffer[i] == 10) {
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen /* got it */
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen ret_buf = i_stream_next_line_finish(_stream, i);
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen break;
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen }
64541374b58e4c702b1926e87df421d180ffa006Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (ret_buf == NULL)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return i_stream_last_line(_stream);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return ret_buf;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenchar *i_stream_read_next_line(struct istream *stream)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen char *line;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen for (;;) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen line = i_stream_next_line(stream);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (line != NULL)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen break;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (i_stream_read(stream) <= 0)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen return i_stream_last_line(stream->real_stream);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return line;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainenconst unsigned char *
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Siraineni_stream_get_data(const struct istream *stream, size_t *size_r)
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const struct istream_private *_stream = stream->real_stream;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (_stream->skip >= _stream->pos) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *size_r = 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return NULL;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *size_r = _stream->pos - _stream->skip;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return _stream->buffer + _stream->skip;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenunsigned char *i_stream_get_modifiable_data(const struct istream *stream,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen size_t *size_r)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const struct istream_private *_stream = stream->real_stream;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *size_r = 0;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen return NULL;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *size_r = _stream->pos - _stream->skip;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return _stream->w_buffer + _stream->skip;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen size_t *size_r, size_t threshold)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen ssize_t ret = 0;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen bool read_more = FALSE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen do {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *data_r = i_stream_get_data(stream, size_r);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (*size_r > threshold)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* we need more data */
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen ret = i_stream_read(stream);
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen if (ret > 0)
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen read_more = TRUE;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen } while (ret > 0);
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *data_r = i_stream_get_data(stream, size_r);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (ret == -2)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -2;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (ret == 0) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* need to read more */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(!stream->blocking);
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen return 0;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (stream->eof) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (read_more) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* we read at least some new data */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(stream->stream_errno != 0);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return -1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->pos - stream->skip);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->pos -= stream->skip;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->skip = 0;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen size_t old_size;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen old_size = stream->buffer_size;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->buffer_size = stream->pos + bytes;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->buffer_size = stream->init_buffer_size;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen else
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
871c7b8969e8627dc4c8b3e56fd126f948e6bce6Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (stream->max_buffer_size > 0 &&
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->buffer_size > stream->max_buffer_size)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->buffer_size = stream->max_buffer_size;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (stream->buffer_size <= old_size)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen stream->buffer_size = old_size;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->buffer_size);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen stream->buffer = stream->w_buffer;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen}
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenbool i_stream_get_buffer_space(struct istream_private *stream,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen size_t wanted_size, size_t *size_r)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(wanted_size > 0);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (stream->skip > 0) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* remove the unused bytes from beginning of buffer */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_stream_compress(stream);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else if (stream->max_buffer_size == 0 ||
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* buffer is full - grow it */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (size_r != NULL)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *size_r = stream->buffer_size - stream->pos;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return stream->pos != stream->buffer_size;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen size_t size)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct istream_private *stream = _stream->real_stream;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen size_t size2;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen (void)i_stream_get_buffer_space(stream, size, &size2);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (size > size2)
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen return FALSE;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen stream->pos += size;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return TRUE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t max_size)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen{
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen _stream->max_buffer_size = max_size;
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen if (_stream->parent != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(_stream->w_buffer);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (_stream->parent != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_unref(&_stream->parent);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
8830fab191cab8440281eb641dfdd93974b2933bTimo Sirainenstatic void
b2105c78f0fd58281317e6d777ded860f33153a3Timo Siraineni_stream_default_seek(struct istream_private *stream,
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t available;
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (stream->istream.v_offset > v_offset)
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen i_panic("stream doesn't support seeking backwards");
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (stream->istream.v_offset < v_offset) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)i_stream_read(&stream->istream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen available = stream->pos - stream->skip;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (available == 0) {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen stream->istream.stream_errno = ESPIPE;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen return;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen }
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (available <= v_offset - stream->istream.v_offset)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen i_stream_skip(&stream->istream, available);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen else {
e12648867876aaec17e06ee4caef0bb60363449dTimo Sirainen i_stream_skip(&stream->istream,
e12648867876aaec17e06ee4caef0bb60363449dTimo Sirainen v_offset - stream->istream.v_offset);
e12648867876aaec17e06ee4caef0bb60363449dTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic const struct stat *
d482b35af87f5fd872bad007da0475813a401a49Timo Siraineni_stream_default_stat(struct istream_private *stream, bool exact ATTR_UNUSED)
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return &stream->statbuf;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Siraineni_stream_default_get_size(struct istream_private *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool exact, uoff_t *size_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen const struct stat *st;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen st = stream->stat(stream, exact);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (st == NULL)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (st->st_size == -1)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *size_r = st->st_size;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return 1;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainenstruct istream *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen _stream->fd = fd;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (parent != NULL) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen _stream->access_counter = parent->real_stream->access_counter;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen _stream->parent = parent;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen _stream->parent_start_offset = parent->v_offset;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen _stream->parent_expected_offset = parent->v_offset;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen _stream->abs_start_offset = parent->v_offset +
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen parent->real_stream->abs_start_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_ref(parent);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen _stream->istream.real_stream = _stream;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (_stream->iostream.destroy == NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen _stream->iostream.destroy = i_stream_default_destroy;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (_stream->seek == NULL) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_assert(!_stream->istream.seekable);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen _stream->seek = i_stream_default_seek;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (_stream->stat == NULL)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen _stream->stat = i_stream_default_stat;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (_stream->get_size == NULL)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen _stream->get_size = i_stream_default_get_size;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen _stream->iostream.set_max_buffer_size =
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_stream_default_set_max_buffer_size;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (_stream->init_buffer_size == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen _stream->init_buffer_size = I_STREAM_MIN_SIZE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen _stream->statbuf.st_size = -1;
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen _stream->statbuf.st_atime =
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen _stream->statbuf.st_mtime =
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen _stream->statbuf.st_ctime = ioloop_time;
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen io_stream_init(&_stream->iostream);
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen return &_stream->istream;
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen}
0ce3bbb0f03fb0ee99258b41b5a1d689c1158a75Timo Sirainen