bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "lib.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "istream-private.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstruct limit_istream {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private istream;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
9511a40d933181045343110c8101b75887062aaeTimo Sirainen uoff_t v_size;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen};
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainenstatic void i_stream_limit_destroy(struct iostream_private *stream)
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen{
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen uoff_t v_offset;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen v_offset = lstream->istream.parent_start_offset +
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen lstream->istream.istream.v_offset;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen if (lstream->istream.parent->seekable ||
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen v_offset > lstream->istream.parent->v_offset) {
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen /* get to same position in parent stream */
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen i_stream_seek(lstream->istream.parent, v_offset);
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen }
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen}
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic ssize_t i_stream_limit_read(struct istream_private *stream)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen uoff_t left;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ssize_t ret;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen size_t pos;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
3f8303bae0f70df6db9337ad1d1476d290f9b1a3Timo Sirainen i_stream_seek(stream->parent, lstream->istream.parent_start_offset +
3f8303bae0f70df6db9337ad1d1476d290f9b1a3Timo Sirainen stream->istream.v_offset);
3f8303bae0f70df6db9337ad1d1476d290f9b1a3Timo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (stream->istream.v_offset +
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen (stream->pos - stream->skip) >= lstream->v_size) {
859cc94211b759825db5e15b0c88754da902ca14Timo Sirainen stream->istream.eof = TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
859cc94211b759825db5e15b0c88754da902ca14Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->pos -= stream->skip;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->skip = 0;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (pos > stream->pos)
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen ret = 0;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen else do {
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen if ((ret = i_stream_read_memarea(stream->parent)) == -2)
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen return -2;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->istream.eof = stream->parent->eof;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen } while (pos <= stream->pos && ret > 0);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (lstream->v_size != (uoff_t)-1) {
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen left = lstream->v_size - stream->istream.v_offset;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (pos >= left) {
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen pos = left;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->istream.eof = TRUE;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen }
1117aa7adc2909c750031fd7551a58a486d100d8Timo Sirainen }
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen (ret == 0 ? 0 : -1);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->pos = pos;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen i_assert(ret != -1 || stream->istream.eof ||
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen stream->istream.stream_errno != 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return ret;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenstatic int
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_limit_stat(struct istream_private *stream, bool exact)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen const struct stat *st;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen stream->statbuf = *st;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (lstream->v_size != (uoff_t)-1)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen stream->statbuf.st_size = lstream->v_size;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenstatic int i_stream_limit_get_size(struct istream_private *stream,
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen bool exact, uoff_t *size_r)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen{
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen const struct stat *st;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (lstream->v_size != (uoff_t)-1) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen *size_r = lstream->v_size;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return 1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (i_stream_stat(&stream->istream, exact, &st) < 0)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return -1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (st->st_size == -1)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return 0;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen *size_r = st->st_size;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return 1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen}
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
10c96a244935de4add8213ba0b894178dfb889a5Timo Sirainenstruct istream *i_stream_create_limit(struct istream *input, uoff_t v_size)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct limit_istream *lstream;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen lstream = i_new(struct limit_istream, 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen lstream->v_size = v_size;
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen lstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen lstream->istream.iostream.destroy = i_stream_limit_destroy;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen lstream->istream.read = i_stream_limit_read;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen lstream->istream.stat = i_stream_limit_stat;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen lstream->istream.get_size = i_stream_limit_get_size;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen lstream->istream.istream.readable_fd = input->readable_fd;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen lstream->istream.istream.blocking = input->blocking;
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen lstream->istream.istream.seekable = input->seekable;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen return i_stream_create(&lstream->istream, input,
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen i_stream_get_fd(input), 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainenstruct istream *i_stream_create_range(struct istream *input,
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen uoff_t v_offset, uoff_t v_size)
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen{
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen uoff_t orig_offset = input->v_offset;
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen struct istream *ret;
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen input->v_offset = v_offset;
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen ret = i_stream_create_limit(input, v_size);
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen input->v_offset = orig_offset;
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen return ret;
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen}