istream.c revision 45312f52ff3a3d4c137447be4c7556500c2f8bf2
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "ioloop.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "str.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream-internal.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenvoid i_stream_destroy(struct istream **stream)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen{
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_stream_close(*stream);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_stream_unref(stream);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_ref(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid i_stream_unref(struct istream **stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (_stream->iostream.refcount == 1) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (_stream->line_str != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str_free(&_stream->line_str);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_unref(&(*stream)->real_stream->iostream);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *stream = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen#undef i_stream_set_destroy_callback
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenvoid i_stream_set_destroy_callback(struct istream *stream,
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen istream_callback_t *callback, void *context)
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen{
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen iostream->destroy_callback = callback;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen iostream->destroy_context = context;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen}
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenint i_stream_get_fd(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->fd;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_close(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_close(&stream->real_stream->iostream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->closed = TRUE;
7db932bd4934cd967eeae643300aef5b91caeaeaTimo Sirainen
7db932bd4934cd967eeae643300aef5b91caeaeaTimo Sirainen if (stream->stream_errno == 0)
74066569545099304b20e790df7c261883d1746bTimo Sirainen stream->stream_errno = ENOENT;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen stream->real_stream->return_nolf_line = set;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenssize_t i_stream_read(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen ssize_t ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen stream->eof = FALSE;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen stream->stream_errno = 0;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen ret = _stream->read(_stream);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen switch (ret) {
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen case -2:
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen i_assert(_stream->skip != _stream->pos);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen break;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen case -1:
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (stream->stream_errno != 0) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* error handling should be easier if we now just
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen assume the stream is now at EOF */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen stream->eof = TRUE;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen } else {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_assert(stream->eof);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen break;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen case 0:
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen i_assert(!stream->blocking);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen break;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t data_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen data_size = _stream->pos - _stream->skip;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen if (count <= data_size) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* within buffer */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->v_offset += count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->skip += count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* have to seek forward */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen count -= data_size;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen _stream->skip = _stream->pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->v_offset += data_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen stream->stream_errno = 0;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream *stream)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen{
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen uoff_t expected_offset;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (stream->real_stream->parent == NULL)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return TRUE;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen /* use the fast route only if the parent stream is at the
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen expected offset */
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen expected_offset = stream->real_stream->parent_start_offset +
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen stream->v_offset - stream->real_stream->skip;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (stream->real_stream->parent->v_offset != expected_offset)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return FALSE;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return i_stream_can_optimize_seek(stream->real_stream->parent);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen}
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (v_offset >= stream->v_offset &&
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen i_stream_can_optimize_seek(stream)) {
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen return;
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen }
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen stream->eof = FALSE;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, v_offset, FALSE);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen}
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen stream->eof = FALSE;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, v_offset, TRUE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenvoid i_stream_sync(struct istream *stream)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen return;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (_stream->sync != NULL)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->sync(_stream);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenconst struct stat *i_stream_stat(struct istream *stream, bool exact)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(stream->closed))
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen return NULL;
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen return _stream->stat(_stream, exact);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenbool i_stream_have_bytes_left(const struct istream *stream)
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return !stream->eof || _stream->skip != _stream->pos;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen}
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen char *ret;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen size_t end;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (i > 0 && stream->buffer[i-1] == '\r')
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end = i - 1;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen else
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end = i;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (stream->w_buffer != NULL) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* modify the buffer directly */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->w_buffer[end] = '\0';
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen } else {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* use a temporary string to return it */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (stream->line_str == NULL)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->line_str = str_new(default_pool, 256);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen str_truncate(stream->line_str, 0);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end - stream->skip);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen ret = str_c_modifiable(stream->line_str);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (i < stream->pos)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen i++;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->istream.v_offset += i - stream->skip;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->skip = i;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen return ret;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen _stream->return_nolf_line) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* the last line is missing LF and we want to return it. */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return NULL;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenchar *i_stream_next_line(struct istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen char *ret_buf;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t i;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen if (_stream->skip >= _stream->pos) {
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen stream->stream_errno = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(_stream->w_buffer == NULL)) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_error("i_stream_next_line() called for unmodifiable stream");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* @UNSAFE */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret_buf = NULL;
3e25b17126e9536736d5da03697613e4c3af5f76Timo Sirainen for (i = _stream->skip; i < _stream->pos; i++) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->buffer[i] == 10) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* got it */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret_buf = i_stream_next_line_finish(_stream, i);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (ret_buf == NULL)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_last_line(_stream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return ret_buf;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenchar *i_stream_read_next_line(struct istream *stream)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen{
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen char *line;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen for (;;) {
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen line = i_stream_next_line(stream);
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen if (line != NULL)
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen break;
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen if (i_stream_read(stream) <= 0)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_last_line(stream->real_stream);
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return line;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen}
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenconst unsigned char *
68a4946b12583b88fa802e52ebee45cd96056772Timo Siraineni_stream_get_data(const struct istream *stream, size_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = _stream->pos - _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->buffer + _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenunsigned char *i_stream_get_modifiable_data(const struct istream *stream,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen size_t *size_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *size_r = _stream->pos - _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _stream->w_buffer + _stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen size_t *size_r, size_t threshold)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ssize_t ret = 0;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool read_more = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen do {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (*size_r > threshold)
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen return 1;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we need more data */
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen ret = i_stream_read(stream);
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen if (ret > 0)
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen read_more = TRUE;
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen } while (ret > 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen *data_r = i_stream_get_data(stream, size_r);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (ret == -2)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return -2;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen if (ret == 0) {
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen /* need to read more */
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen i_assert(!stream->blocking);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return 0;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (stream->eof) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (read_more) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* we read at least some new data */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return 0;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen } else {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_assert(stream->stream_errno != 0);
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen }
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen{
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->pos - stream->skip);
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->pos -= stream->skip;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen stream->skip = 0;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen}
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen size_t old_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen old_size = stream->buffer_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = stream->pos + bytes;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (stream->buffer_size <= I_STREAM_MIN_SIZE)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = I_STREAM_MIN_SIZE;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen else
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (stream->max_buffer_size > 0 &&
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size > stream->max_buffer_size)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = stream->max_buffer_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer = stream->w_buffer =
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen i_realloc(stream->w_buffer, old_size, stream->buffer_size);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainenbool i_stream_get_buffer_space(struct istream_private *stream,
14175321ddb88619015866978c05a27786ca4814Timo Sirainen size_t wanted_size, size_t *size_r)
14175321ddb88619015866978c05a27786ca4814Timo Sirainen{
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_assert(wanted_size > 0);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen if (stream->skip > 0) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* remove the unused bytes from beginning of buffer */
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_stream_compress(stream);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen } else if (stream->max_buffer_size == 0 ||
14175321ddb88619015866978c05a27786ca4814Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* buffer is full - grow it */
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen }
14175321ddb88619015866978c05a27786ca4814Timo Sirainen }
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainen if (size_r != NULL)
14175321ddb88619015866978c05a27786ca4814Timo Sirainen *size_r = stream->buffer_size - stream->pos;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen return stream->pos != stream->buffer_size;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen}
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen size_t size)
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen{
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen struct istream_private *stream = _stream->real_stream;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen size_t size2;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen (void)i_stream_get_buffer_space(stream, size, &size2);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen if (size > size2)
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen return FALSE;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen stream->pos += size;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen return TRUE;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen}
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen size_t max_size)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen _stream->max_buffer_size = max_size;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenstatic const struct stat *
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_default_stat(struct istream_private *stream, bool exact ATTR_UNUSED)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return &stream->statbuf;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainenstruct istream *
9511a40d933181045343110c8101b75887062aaeTimo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->fd = fd;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen if (parent != NULL) {
9511a40d933181045343110c8101b75887062aaeTimo Sirainen _stream->parent = parent;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen _stream->parent_start_offset = parent->v_offset;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen _stream->abs_start_offset = parent->v_offset +
9511a40d933181045343110c8101b75887062aaeTimo Sirainen parent->real_stream->abs_start_offset;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->istream.real_stream = _stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (_stream->stat == NULL)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen _stream->stat = i_stream_default_stat;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen _stream->iostream.set_max_buffer_size =
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_stream_default_set_max_buffer_size;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_size = -1;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_atime =
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_mtime =
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen _stream->statbuf.st_ctime = ioloop_time;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_init(&_stream->iostream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return &_stream->istream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#ifdef STREAM_TEST
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen/* gcc istream.c -o teststream liblib.a -Wall -DHAVE_CONFIG_H -DSTREAM_TEST -g */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include <fcntl.h>
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include <unistd.h>
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "ostream.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#define BUF_VALUE(offset) \
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen (((offset) % 256) ^ ((offset) / 256))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic void check_buffer(const unsigned char *data, size_t size, size_t offset)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen size_t i;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < size; i++)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(data[i] == BUF_VALUE(i+offset));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenint main(void)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct istream *input, *l_input;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct ostream *output1, *output2;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen int i, fd1, fd2;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unsigned char buf[1024];
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen const unsigned char *data;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen size_t size;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen lib_init();
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen fd1 = open("teststream.1", O_RDWR | O_CREAT | O_TRUNC, 0600);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (fd1 < 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_fatal("open() failed: %m");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen fd2 = open("teststream.2", O_RDWR | O_CREAT | O_TRUNC, 0600);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (fd2 < 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_fatal("open() failed: %m");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* write initial data */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < sizeof(buf); i++)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen buf[i] = BUF_VALUE(i);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen write(fd1, buf, sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test reading */
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen input = i_stream_create_fd(fd1, 512, FALSE);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_get_size(input) == sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, size, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 256);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, size, 256);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 512) == -2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, size, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_skip(input, 900);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == sizeof(buf) - 900);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, size, 900);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test moving data */
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen output1 = o_stream_create_fd(fd1, 512, FALSE);
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen output2 = o_stream_create_fd(fd2, 512, FALSE);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 1); size = sizeof(buf)-1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output2, input) == size);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen o_stream_flush(output2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen lseek(fd2, 0, SEEK_SET);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(read(fd2, buf, sizeof(buf)) == size);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(buf, size, 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen o_stream_seek(output1, sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output1, input) == sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test moving with limits */
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen l_input = i_stream_create_limit(input, sizeof(buf)/2, 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(l_input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen o_stream_seek(output1, 10);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output1, l_input) == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_set_max_buffer_size(input, sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, sizeof(buf)-1) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data, 10, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data + 10, 512, sizeof(buf)/2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen check_buffer(data + 10 + 512,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen size - (10 + 512), 10 + 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* reading within limits */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(l_input, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 511) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 512) == -2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_skip(l_input, 511);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_skip(l_input, 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 0) == -1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(size == 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unlink("teststream.1");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unlink("teststream.2");
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#endif