istream-seekable.c revision 252db51b6c0a605163326b3ea5d09e9936ca3b29
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen/* Copyright (C) 2005 Timo Sirainen */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int cur_idx;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void _close(struct iostream_private *stream ATTR_UNUSED)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int i;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void _destroy(struct iostream_private *stream)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int i;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen_set_max_buffer_size(struct iostream_private *stream, size_t max_size)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int i;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_set_max_buffer_size(sstream->fd_input, max_size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_set_max_buffer_size(sstream->input[i], max_size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic int copy_to_temp_file(struct seekable_istream *sstream)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* create a temporary file */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen fd = open(path, O_RDWR | O_EXCL | O_CREAT, 0600);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* we just want the fd, unlink it */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* shouldn't happen.. */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* copy our currently read buffer to it */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (write_full(fd, sstream->buffer->data, sstream->buffer->used) < 0) {
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen i_stream_create_fd(fd, sstream->max_buffer_size, TRUE);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic ssize_t read_more(struct seekable_istream *sstream)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen while ((ret = i_stream_read(sstream->cur_input)) < 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* go to next stream */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->cur_input = sstream->input[sstream->cur_idx++];
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* last one, EOF */
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen /* see if stream has pending data */
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen (void)i_stream_get_data(sstream->cur_input, &size);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool read_from_buffer(struct seekable_istream *sstream, ssize_t *ret)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *stream = &sstream->istream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const unsigned char *data;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen (stream->pos - stream->skip) >= sstream->buffer->used) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* need to read more */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->buffer->used >= sstream->max_buffer_size)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* read more to buffer */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* we should have more now. */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen data = i_stream_get_data(sstream->cur_input, &size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen stream->buffer = CONST_PTR_OFFSET(sstream->buffer->data, offset);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic ssize_t _read(struct istream_private *stream)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const unsigned char *data;
8d235b34022f0bf0f7db54fdbda2d4fd204ed864Timo Sirainen stream->buffer = CONST_PTR_OFFSET(stream->buffer, stream->skip);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* copy everything to temp file and use it as the stream */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen while (stream->istream.v_offset + stream->pos >= sstream->write_peak) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* need to read more */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* save to our file */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen data = i_stream_get_data(sstream->cur_input, &size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (write_full(sstream->fd, data, size) < 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_seek(sstream->fd_input, stream->istream.v_offset);
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen stream->buffer = i_stream_get_data(sstream->fd_input, &pos);
4da70fe8c9cb6e57b36103d78ab1e9c8654f76d9Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : ret;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void _seek(struct istream_private *stream, uoff_t v_offset,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic const struct stat *_stat(struct istream_private *stream, bool exact)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen /* we want to know the full size of the file, so read until
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen we're finished */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_skip(&stream->istream, stream->skip);
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen i_panic("i_stream_stat() used for non-blocking "
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen "seekable stream");
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen /* using a file backed buffer, we can use real fstat() */
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen return i_stream_stat(sstream->fd_input, exact);
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen /* buffer is completely in memory */
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen stream->statbuf.st_size = sstream->buffer->used;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Siraineni_stream_create_seekable(struct istream *input[],
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen size_t max_buffer_size, const char *temp_prefix)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const unsigned char *data;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int count;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen for (count = 0; input[count] != NULL; count++)
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen sstream->buffer = buffer_create_dynamic(default_pool, BUF_INITIAL_SIZE);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen sstream->input = i_new(struct istream *, count + 1);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen memcpy(sstream->input, input, sizeof(*input) * count);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* initialize our buffer from first stream's pending data */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen data = i_stream_get_data(sstream->cur_input, &size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return i_stream_create(&sstream->istream, -1, 0);