istream.c revision 6657aee0bb6c603b4ee5111388b93c1a8a9ad680
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "array.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "str.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "istream-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free(stream->real_stream->iostream.name);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->real_stream->iostream.name = i_strdup(name);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *i_stream_get_name(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream = stream->real_stream->parent;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return "";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return stream->real_stream->iostream.name;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen{
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen stream->closed = TRUE;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (stream->stream_errno == 0)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen stream->stream_errno = EPIPE;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenvoid i_stream_destroy(struct istream **stream)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_close_full(*stream, FALSE);
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen i_stream_unref(stream);
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_ref(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_unref(struct istream **stream)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (_stream->iostream.refcount == 1) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (_stream->line_str != NULL)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen str_free(&_stream->line_str);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (!io_stream_unref(&(*stream)->real_stream->iostream)) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if ((*stream)->real_stream->parent != NULL)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_stream_unref(&(*stream)->real_stream->parent);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_free(&(*stream)->real_stream->iostream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen *stream = NULL;
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#undef i_stream_add_destroy_callback
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen istream_callback_t *callback, void *context)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen callback, context);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen void (*callback)())
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen callback);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint i_stream_get_fd(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return _stream->fd;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *i_stream_get_error(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream *s;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we'll only return errors for streams that have stream_errno set or
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen that have reached EOF. we might be returning unintended error
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen otherwise. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->stream_errno == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return stream->eof ? "EOF" : "<no error>";
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (s->stream_errno == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (s->real_stream->iostream.error != NULL)
b34fdb68d376d85b4880da4a4bdf67ae726a381bTimo Sirainen return s->real_stream->iostream.error;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return strerror(stream->stream_errno);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *i_stream_get_disconnect_reason(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return io_stream_get_disconnect_reason(stream, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_close(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_stream_close_full(stream, TRUE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->real_stream->init_buffer_size = size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t max_size = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen do {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (max_size < stream->real_stream->max_buffer_size)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen max_size = stream->real_stream->max_buffer_size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream = stream->real_stream->parent;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } while (stream != NULL);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen return max_size;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen}
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen{
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen stream->real_stream->return_nolf_line = set;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen}
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenvoid i_stream_set_persistent_buffers(struct istream *stream, bool set)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen do {
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen stream->real_stream->nonpersistent_buffers = !set;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen stream = stream->real_stream->parent;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen } while (stream != NULL);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen}
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen{
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen if (stream->parent == NULL)
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen stream->access_counter++;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen else {
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen stream->access_counter =
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen stream->parent->real_stream->access_counter;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen }
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen}
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenssize_t i_stream_read(struct istream *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen size_t old_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ssize_t ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->eof = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen errno = stream->stream_errno;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen stream->eof = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->parent != NULL)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen old_size = _stream->pos - _stream->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = _stream->read(_stream);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen switch (ret) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen case -2:
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_assert(_stream->skip != _stream->pos);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen break;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen case -1:
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (stream->stream_errno != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* error handling should be easier if we now just
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen assume the stream is now at EOF */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->eof = TRUE;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen errno = stream->stream_errno;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert(stream->eof);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen break;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen case 0:
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_assert(!stream->blocking);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen default:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(ret > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(_stream->skip < _stream->pos);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->stream_errno != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* error handling should be easier if we now just
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen assume the stream is now at EOF. Note that we could get here
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen even if read() didn't return -1, although that's a little
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bit sloppy istream implementation. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->eof = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_update(_stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* verify that parents' access_counters are valid. the parent's
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_read() should guarantee this. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(!i_stream_is_buffer_invalid(_stream));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *stream = istream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ssize_t ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->pos -= stream->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->skip = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (pos > stream->pos)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else do {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_update(stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -2;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.eof = stream->parent->eof;
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen /* check again, in case the parent stream had been seeked
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen backwards and the previous read() didn't get us far
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enough. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } while (pos <= stream->pos && ret > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (ret == 0 ? 0 : -1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->pos = pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(ret != -1 || stream->istream.eof ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.stream_errno != 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_update(stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t data_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen data_size = _stream->pos - _stream->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (count <= data_size) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* within buffer */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->v_offset += count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->skip += count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->nonpersistent_buffers &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->skip == _stream->pos) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->skip = _stream->pos = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->buffer_size = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free_and_null(_stream->w_buffer);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* have to seek forward */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen count -= data_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->skip = _stream->pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->v_offset += data_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->parent == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen /* use the fast route only if the parent stream hasn't been changed */
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (stream->access_counter !=
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen stream->parent->real_stream->access_counter)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen return FALSE;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen}
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (v_offset >= stream->v_offset &&
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen i_stream_can_optimize_seek(_stream))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->eof = FALSE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen _stream->seek(_stream, v_offset, FALSE);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_stream_update(_stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->eof = FALSE;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen _stream->seek(_stream, v_offset, TRUE);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_stream_update(_stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volkvoid i_stream_sync(struct istream *stream)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen struct istream_private *_stream = stream->real_stream;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen return;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (_stream->sync != NULL) {
02a6291366caff79793db35d479e2a062bec2af4Timo Sirainen _stream->sync(_stream);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_update(_stream);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen }
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen}
573085b4b25b0bbae8d27969df2c91702eefa23eTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen if (_stream->stat(_stream, exact) < 0)
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen return -1;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen *st_r = &_stream->statbuf;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen return 0;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return _stream->get_size(_stream, exact, size_r);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen return i_stream_get_data_size(stream) > 0 || !stream->eof;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenbool i_stream_is_eof(struct istream *stream)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (i_stream_get_data_size(stream) == 0)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen (void)i_stream_read(stream);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen return !i_stream_have_bytes_left(stream);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen uoff_t abs_offset = stream->v_offset;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen while (stream != NULL) {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen abs_offset += stream->real_stream->start_offset;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen stream = stream->real_stream->parent;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen }
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen return abs_offset;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen{
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen char *ret;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen size_t end;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r') {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen end = i - 1;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen stream->line_crlf = TRUE;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen } else {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen end = i;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen stream->line_crlf = FALSE;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen }
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (stream->buffer == stream->w_buffer) {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen /* modify the buffer directly */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen stream->w_buffer[end] = '\0';
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen } else {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen /* use a temporary string to return it */
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (stream->line_str == NULL)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen stream->line_str = str_new(default_pool, 256);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen str_truncate(stream->line_str, 0);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen end - stream->skip);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = str_c_modifiable(stream->line_str);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (i < stream->pos)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen i++;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen stream->istream.v_offset += i - stream->skip;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen stream->skip = i;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return ret;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen _stream->return_nolf_line) {
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen /* the last line is missing LF and we want to return it. */
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return NULL;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenchar *i_stream_next_line(struct istream *stream)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct istream_private *_stream = stream->real_stream;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen const unsigned char *pos;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (_stream->skip >= _stream->pos)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return NULL;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen _stream->pos - _stream->skip);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (pos != NULL) {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return i_stream_next_line_finish(_stream,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen pos - _stream->buffer);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen } else {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return i_stream_last_line(_stream);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen }
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenchar *i_stream_read_next_line(struct istream *stream)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen char *line;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen for (;;) {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen line = i_stream_next_line(stream);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (line != NULL)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen break;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen switch (i_stream_read(stream)) {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen case -2:
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen io_stream_set_error(&stream->real_stream->iostream,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "Line is too long (over %"PRIuSIZE_T
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen " bytes at offset %"PRIuUOFF_T")",
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_get_data_size(stream), stream->v_offset);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->stream_errno = errno = ENOBUFS;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->eof = TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return NULL;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen case -1:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return i_stream_last_line(stream->real_stream);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen case 0:
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return NULL;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen }
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return line;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return stream->real_stream->line_crlf;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (stream->parent == NULL) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* the buffer can't point to parent, because it doesn't exist */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return FALSE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (stream->w_buffer != NULL) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* we can pretty safely assume that the stream is using its
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen own private buffer, so it can never become invalid. */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return FALSE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen if (stream->access_counter !=
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen stream->parent->real_stream->access_counter) {
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen /* parent has been modified behind this stream, we can't trust
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen that our buffer is valid */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return i_stream_is_buffer_invalid(stream->parent->real_stream);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenconst unsigned char *
2eb0402a28bd0422e0170160808c67d6c7274689Timo Siraineni_stream_get_data(struct istream *stream, size_t *size_r)
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct istream_private *_stream = stream->real_stream;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen if (_stream->skip >= _stream->pos) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *size_r = 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return &uchar_nul;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (i_stream_is_buffer_invalid(_stream)) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* This stream may be using parent's buffer directly as
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen _stream->buffer, but the parent stream has already been
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen modified indirectly. This means that the buffer might no
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen longer point to where we assume it points to. So we'll
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen just return the stream as empty until it's read again.
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen It's a bit ugly to suddenly drop data from the stream that
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen was already read, but since this happens only with shared
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen parent istreams the caller is hopefully aware enough that
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen something like this might happen. The other solutions would
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen be to a) try to automatically read the data back (but we
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen can't handle errors..) or b) always copy data to stream's
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen own buffer instead of pointing to parent's buffer (but this
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen causes data copying that is nearly always unnecessary). */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *size_r = 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* if we had already read until EOF, mark the stream again as
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen not being at the end of file. */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (stream->stream_errno == 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen _stream->skip = _stream->pos = 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->eof = FALSE;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen return &uchar_nul;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *size_r = _stream->pos - _stream->skip;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return _stream->buffer + _stream->skip;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainensize_t i_stream_get_data_size(struct istream *stream)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen size_t size;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen (void)i_stream_get_data(stream, &size);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return size;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen size_t *size_r)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen struct istream_private *_stream = stream->real_stream;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *size_r = 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return NULL;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *size_r = _stream->pos - _stream->skip;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return _stream->w_buffer + _stream->skip;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen size_t *size_r, size_t threshold)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ssize_t ret = 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen bool read_more = FALSE;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen do {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (*size_r > threshold)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return 1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen /* we need more data */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen ret = i_stream_read(stream);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (ret > 0)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen read_more = TRUE;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } while (ret > 0);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (ret == -2)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -2;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (ret == 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* need to read more */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_assert(!stream->blocking);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return 0;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (stream->eof) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (read_more) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* we read at least some new data */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen } else {
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen i_assert(stream->stream_errno != 0);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->pos - stream->skip);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->pos -= stream->skip;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->skip = 0;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen size_t old_size, max_size;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen old_size = stream->buffer_size;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->buffer_size = stream->pos + bytes;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->buffer_size = stream->init_buffer_size;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen else
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen max_size = i_stream_get_max_buffer_size(&stream->istream);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_assert(max_size > 0);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (stream->buffer_size > max_size)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->buffer_size = max_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->buffer_size <= old_size)
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen stream->buffer_size = old_size;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen else {
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->buffer_size);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->buffer = stream->w_buffer;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t wanted_size, size_t *size_r)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen i_assert(wanted_size > 0);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->skip > 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* remove the unused bytes from beginning of buffer */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_compress(stream);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen } else if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream)) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* buffer is full - grow it */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen *size_r = stream->buffer_size - stream->pos;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (stream->try_alloc_limit > 0 &&
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen *size_r > stream->try_alloc_limit)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *size_r = stream->try_alloc_limit;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return *size_r > 0;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen size_t old_size, avail_size;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (avail_size < size) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen old_size = stream->buffer_size;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->buffer_size);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen stream->buffer = stream->w_buffer;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_assert(avail_size >= size);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return stream->w_buffer + stream->pos;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen size_t size)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct istream_private *stream = _stream->real_stream;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen size_t size2;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_try_alloc(stream, size, &size2);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (size > size2)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return FALSE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->pos += size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (!pending)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen while (stream->real_stream->parent != NULL) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_assert(stream->real_stream->io == NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream = stream->real_stream->parent;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (stream->real_stream->io != NULL)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen io_set_pending(stream->real_stream->io);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid i_stream_switch_ioloop(struct istream *stream)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen do {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stream->real_stream->switch_ioloop != NULL)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->real_stream->switch_ioloop(stream->real_stream);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream = stream->real_stream->parent;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } while (stream != NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid i_stream_set_io(struct istream *stream, struct io *io)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen while (stream->real_stream->parent != NULL) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_assert(stream->real_stream->io == NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream = stream->real_stream->parent;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen }
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_assert(stream->real_stream->io == NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->real_stream->io = io;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainenvoid i_stream_unset_io(struct istream *stream, struct io *io)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen{
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen while (stream->real_stream->parent != NULL) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_assert(stream->real_stream->io == NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream = stream->real_stream->parent;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen i_assert(stream->real_stream->io == io);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen stream->real_stream->io = NULL;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainenstatic void
f38485358ffc04c3466b917770575e29deef24c3Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen size_t max_size)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen _stream->max_buffer_size = max_size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->parent != NULL)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen}
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenstatic void i_stream_default_close(struct iostream_private *stream,
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen bool close_parent)
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen{
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (close_parent && _stream->parent != NULL)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_close(_stream->parent);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free(_stream->w_buffer);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (_stream->parent != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_unref(&_stream->parent);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainenstatic void
f38485358ffc04c3466b917770575e29deef24c3Timo Siraineni_stream_default_seek_seekable(struct istream_private *stream,
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->istream.v_offset = v_offset;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->skip = stream->pos = 0;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid i_stream_default_seek_nonseekable(struct istream_private *stream,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen size_t available;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (stream->istream.v_offset > v_offset)
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen i_panic("stream %s doesn't support seeking backwards",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_get_name(&stream->istream));
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen while (stream->istream.v_offset < v_offset) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)i_stream_read(&stream->istream);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen available = stream->pos - stream->skip;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (available == 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (stream->istream.stream_errno != 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* read failed */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen io_stream_set_error(&stream->iostream,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "Can't seek to offset %"PRIuUOFF_T
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ", because we have data only up to offset %"
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen PRIuUOFF_T" (eof=%d)", v_offset,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->istream.v_offset, stream->istream.eof ? 1 : 0);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->istream.stream_errno = ESPIPE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (available <= v_offset - stream->istream.v_offset)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_skip(&stream->istream, available);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen else {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_skip(&stream->istream,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen v_offset - stream->istream.v_offset);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Siraineni_stream_default_stat(struct istream_private *stream, bool exact)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const struct stat *st;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (stream->parent == NULL)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return stream->istream.stream_errno == 0 ? 0 : -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen return -1;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen }
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen stream->statbuf = *st;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen if (exact && !stream->stream_size_passthrough) {
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen /* exact size is not known, even if parent returned something */
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen stream->statbuf.st_size = -1;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen }
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen return 0;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen}
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainenstatic int
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Siraineni_stream_default_get_size(struct istream_private *stream,
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen bool exact, uoff_t *size_r)
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen{
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen if (stream->stat(stream, exact) < 0)
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen return -1;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen if (stream->statbuf.st_size == -1)
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen return 0;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen *size_r = stream->statbuf.st_size;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen return 1;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen}
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainenvoid i_stream_init_parent(struct istream_private *_stream,
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen struct istream *parent)
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen _stream->access_counter = parent->real_stream->access_counter;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen _stream->parent = parent;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen _stream->parent_start_offset = parent->v_offset;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen _stream->parent_expected_offset = parent->v_offset;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen _stream->start_offset = parent->v_offset;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen /* if parent stream is an istream-error, copy the error */
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen _stream->istream.stream_errno = parent->stream_errno;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen _stream->istream.eof = parent->eof;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen i_stream_ref(parent);
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct istream *
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen{
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen _stream->fd = fd;
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen if (parent != NULL)
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen i_stream_init_parent(_stream, parent);
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen _stream->istream.real_stream = _stream;
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen if (_stream->iostream.close == NULL)
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen _stream->iostream.close = i_stream_default_close;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->iostream.destroy == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->iostream.destroy = i_stream_default_destroy;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->seek == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->seek = _stream->istream.seekable ?
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_default_seek_seekable :
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen i_stream_default_seek_nonseekable;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->stat == NULL)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen _stream->stat = i_stream_default_stat;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->get_size == NULL)
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen _stream->get_size = i_stream_default_get_size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen _stream->iostream.set_max_buffer_size =
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_stream_default_set_max_buffer_size;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (_stream->init_buffer_size == 0)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen _stream->init_buffer_size = I_STREAM_MIN_SIZE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen _stream->statbuf.st_size = -1;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen _stream->statbuf.st_atime =
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen _stream->statbuf.st_mtime =
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen _stream->statbuf.st_ctime = ioloop_time;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen io_stream_init(&_stream->iostream);
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen return &_stream->istream;
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen}
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainenstruct istream *i_stream_create_error(int stream_errno)
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private *stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen stream = i_new(struct istream_private, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.closed = TRUE;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen stream->istream.readable_fd = FALSE;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen stream->istream.blocking = TRUE;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen stream->istream.seekable = TRUE;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen stream->istream.eof = TRUE;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen stream->istream.stream_errno = stream_errno;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_create(stream, NULL, -1);
i_stream_set_name(&stream->istream, "(error)");
return &stream->istream;
}
struct istream *
i_stream_create_error_str(int stream_errno, const char *fmt, ...)
{
struct istream *input;
va_list args;
va_start(args, fmt);
input = i_stream_create_error(stream_errno);
io_stream_set_verror(&input->real_stream->iostream, fmt, args);
va_end(args);
return input;
}