istream-limit.c revision 032964c7cc6788188b63ae6270fc26cbd4a3ca26
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "istream-private.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainenstruct limit_istream {
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen struct istream_private istream;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen uoff_t v_size;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen};
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenstatic void i_stream_limit_destroy(struct iostream_private *stream)
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen{
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen uoff_t v_offset;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen v_offset = lstream->istream.parent_start_offset +
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen lstream->istream.istream.v_offset;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if (lstream->istream.parent->seekable ||
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen v_offset > lstream->istream.parent->v_offset) {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen /* get to same position in parent stream */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_stream_seek(lstream->istream.parent, v_offset);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_stream_unref(&lstream->istream.parent);
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainenstatic ssize_t i_stream_limit_read(struct istream_private *stream)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen uoff_t left;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ssize_t ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen size_t pos;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (stream->istream.v_offset +
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (stream->pos - stream->skip) >= lstream->v_size) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen stream->istream.eof = TRUE;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen return -1;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen }
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen i_stream_seek(stream->parent, lstream->istream.parent_start_offset +
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen stream->istream.v_offset);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen stream->pos -= stream->skip;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen stream->skip = 0;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainen if (pos > stream->pos)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ret = 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen else do {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if ((ret = i_stream_read(stream->parent)) == -2)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return -2;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen stream->istream.eof = stream->parent->eof;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen } while (pos <= stream->pos && ret > 0);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (lstream->v_size != (uoff_t)-1) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen left = lstream->v_size - stream->istream.v_offset;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (pos >= left) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pos = left;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen stream->istream.eof = TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (ret == 0 ? 0 : -1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen stream->pos = pos;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(ret != -1 || stream->istream.eof ||
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen stream->istream.stream_errno != 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic const struct stat *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Siraineni_stream_limit_stat(struct istream_private *stream, bool exact)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen const struct stat *st;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen st = i_stream_stat(stream->parent, exact);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (st == NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen stream->statbuf = *st;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (lstream->v_size != (uoff_t)-1)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen stream->statbuf.st_size = lstream->v_size;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return &stream->statbuf;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int i_stream_limit_get_size(struct istream_private *stream,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen bool exact, uoff_t *size_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct limit_istream *lstream = (struct limit_istream *) stream;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const struct stat *st;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (lstream->v_size != (uoff_t)-1) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *size_r = lstream->v_size;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen return 1;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen st = i_stream_stat(&stream->istream, exact);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (st == NULL)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen return -1;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (st->st_size == -1)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen return 0;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen *size_r = st->st_size;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen return 1;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstruct istream *i_stream_create_limit(struct istream *input, uoff_t v_size)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct limit_istream *lstream;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lstream = i_new(struct limit_istream, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lstream->v_size = v_size;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen lstream->istream.iostream.destroy = i_stream_limit_destroy;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen lstream->istream.parent = input;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen lstream->istream.read = i_stream_limit_read;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen lstream->istream.stat = i_stream_limit_stat;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen lstream->istream.get_size = i_stream_limit_get_size;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen lstream->istream.istream.readable_fd = input->readable_fd;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lstream->istream.istream.blocking = input->blocking;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lstream->istream.istream.seekable = input->seekable;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return i_stream_create(&lstream->istream, input,
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen i_stream_get_fd(input));
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen}
6600c05e2ab38e9f662582b63c56b0c980a03748Timo Sirainen