istream-limit.c revision bdcb00145ad87765e3fd22d4ebc4d2c029a326b9
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "istream-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainenstruct limit_istream {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream_private istream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen uoff_t v_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainenstatic void i_stream_limit_destroy(struct iostream_private *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uoff_t v_offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen v_offset = lstream->istream.parent_start_offset +
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lstream->istream.istream.v_offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lstream->istream.parent->seekable ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen v_offset > lstream->istream.parent->v_offset) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* get to same position in parent stream */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_seek(lstream->istream.parent, v_offset);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_unref(&lstream->istream.parent);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic ssize_t i_stream_limit_read(struct istream_private *stream)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uoff_t left;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ssize_t ret;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen size_t pos;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_stream_seek(stream->parent, lstream->istream.parent_start_offset +
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen stream->istream.v_offset);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (stream->istream.v_offset +
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen (stream->pos - stream->skip) >= lstream->v_size) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen stream->istream.eof = TRUE;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen return -1;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen }
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen stream->pos -= stream->skip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->skip = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo 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 return -2;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen stream->istream.eof = stream->parent->eof;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } while (pos <= stream->pos && ret > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lstream->v_size != (uoff_t)-1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen left = lstream->v_size - stream->istream.v_offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (pos >= left) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen pos = left;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen stream->istream.eof = TRUE;
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen }
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen }
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (ret == 0 ? 0 : -1);
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen stream->pos = pos;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(ret != -1 || stream->istream.eof ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->istream.stream_errno != 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic const struct stat *
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Siraineni_stream_limit_stat(struct istream_private *stream, bool exact)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const struct stat *st;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen st = i_stream_stat(stream->parent, exact);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (st == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->statbuf = *st;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lstream->v_size != (uoff_t)-1)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen stream->statbuf.st_size = lstream->v_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return &stream->statbuf;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int i_stream_limit_get_size(struct istream_private *stream,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool exact, uoff_t *size_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct stat *st;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (lstream->v_size != (uoff_t)-1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *size_r = lstream->v_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen st = i_stream_stat(&stream->istream, exact);
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen if (st == NULL)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return -1;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (st->st_size == -1)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return 0;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen *size_r = st->st_size;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return 1;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen}
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct istream *i_stream_create_limit(struct istream *input, uoff_t v_size)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct limit_istream *lstream;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lstream = i_new(struct limit_istream, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lstream->v_size = v_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen lstream->istream.iostream.destroy = i_stream_limit_destroy;
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen lstream->istream.read = i_stream_limit_read;
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen lstream->istream.stat = i_stream_limit_stat;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lstream->istream.get_size = i_stream_limit_get_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lstream->istream.istream.readable_fd = input->readable_fd;
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainen lstream->istream.istream.blocking = input->blocking;
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen lstream->istream.istream.seekable = input->seekable;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return i_stream_create(&lstream->istream, input,
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen i_stream_get_fd(input));
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainenstruct istream *i_stream_create_range(struct istream *input,
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen uoff_t v_offset, uoff_t v_size)
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen{
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen uoff_t orig_offset = input->v_offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct istream *ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen input->v_offset = v_offset;
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen ret = i_stream_create_limit(input, v_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen input->v_offset = orig_offset;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen