istream-seekable.c revision 252db51b6c0a605163326b3ea5d09e9936ca3b29
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen/* Copyright (C) 2005 Timo Sirainen */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "lib.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "buffer.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "hex-binary.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "randgen.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "write-full.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "istream-internal.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include "istream-seekable.h"
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include <sys/stat.h>
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include <fcntl.h>
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include <unistd.h>
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#include <time.h>
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen#define BUF_INITIAL_SIZE (1024*32)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstruct seekable_istream {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private istream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen size_t max_buffer_size;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen char *temp_prefix;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen uoff_t write_peak;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen buffer_t *buffer;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct istream **input, *cur_input;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct istream *fd_input;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int cur_idx;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen int fd;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen};
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void _close(struct iostream_private *stream ATTR_UNUSED)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int i;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->fd = -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->fd_input != NULL)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_close(sstream->fd_input);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen for (i = 0; sstream->input[i] != NULL; i++)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_close(sstream->input[i]);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void _destroy(struct iostream_private *stream)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int i;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->buffer != NULL)
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen buffer_free(&sstream->buffer);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->fd_input != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_stream_unref(&sstream->fd_input);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen for (i = 0; sstream->input[i] != NULL; i++)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_stream_unref(&sstream->input[i]);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen i_free(sstream->temp_prefix);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen_set_max_buffer_size(struct iostream_private *stream, size_t max_size)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int i;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->max_buffer_size = max_size;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->fd_input != NULL)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_set_max_buffer_size(sstream->fd_input, max_size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen for (i = 0; sstream->input[i] != NULL; i++)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_set_max_buffer_size(sstream->input[i], max_size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic int copy_to_temp_file(struct seekable_istream *sstream)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned char randbuf[8];
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const char *path;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct stat st;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen int fd;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* create a temporary file */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen for (;;) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen random_fill_weak(randbuf, sizeof(randbuf));
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen path = t_strconcat(sstream->temp_prefix, ".",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen dec2str(time(NULL)), ".",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen dec2str(getpid()), ".",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen binary_to_hex(randbuf, sizeof(randbuf)),
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen NULL);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (stat(path, &st) == 0)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen continue;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (errno != ENOENT) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_error("stat(%s) failed: %m", path);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen fd = open(path, O_RDWR | O_EXCL | O_CREAT, 0600);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (fd != -1)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen break;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (errno != EEXIST) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_error("open(%s) failed: %m", path);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* we just want the fd, unlink it */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (unlink(path) < 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* shouldn't happen.. */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_error("unlink(%s) failed: %m", path);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen (void)close(fd);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* copy our currently read buffer to it */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (write_full(fd, sstream->buffer->data, sstream->buffer->used) < 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_error("write_full(%s) failed: %m", path);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen (void)close(fd);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->write_peak = sstream->buffer->used;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen buffer_free(&sstream->buffer);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->fd = fd;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->fd_input =
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen i_stream_create_fd(fd, sstream->max_buffer_size, TRUE);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return 0;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstatic ssize_t read_more(struct seekable_istream *sstream)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen size_t size;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ssize_t ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->cur_input == NULL) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.istream.eof = TRUE;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen while ((ret = i_stream_read(sstream->cur_input)) < 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (!sstream->cur_input->eof) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* error */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.istream.stream_errno =
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->cur_input->stream_errno;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* go to next stream */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->cur_input = sstream->input[sstream->cur_idx++];
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->cur_input == NULL) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* last one, EOF */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.istream.eof = TRUE;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen /* see if stream has pending data */
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen (void)i_stream_get_data(sstream->cur_input, &size);
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen if (size != 0)
5069adb2f5b3609fff9a0a705c6edeae56e0030aTimo Sirainen return size;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool read_from_buffer(struct seekable_istream *sstream, ssize_t *ret)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *stream = &sstream->istream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const unsigned char *data;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen size_t size, pos, offset;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (stream->istream.v_offset +
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 return FALSE;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* read more to buffer */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen *ret = read_more(sstream);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (*ret <= 0)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return TRUE;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* we should have more now. */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen data = i_stream_get_data(sstream->cur_input, &size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen buffer_append(sstream->buffer, data, size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_skip(sstream->cur_input, size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen offset = stream->istream.v_offset;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen stream->buffer = CONST_PTR_OFFSET(sstream->buffer->data, offset);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen pos = sstream->buffer->used - offset;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen *ret = pos - stream->pos;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen stream->pos = pos;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return TRUE;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic ssize_t _read(struct istream_private *stream)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const unsigned char *data;
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen size_t size, pos;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ssize_t ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
8d235b34022f0bf0f7db54fdbda2d4fd204ed864Timo Sirainen stream->buffer = CONST_PTR_OFFSET(stream->buffer, stream->skip);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen stream->pos -= stream->skip;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen stream->skip = 0;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->buffer != NULL) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (read_from_buffer(sstream, &ret))
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* copy everything to temp file and use it as the stream */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (copy_to_temp_file(sstream) < 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_close(&stream->istream);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen i_assert(sstream->buffer == NULL);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen while (stream->istream.v_offset + stream->pos >= sstream->write_peak) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* need to read more */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ret = read_more(sstream);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (ret <= 0)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
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_error("write_full(%s...) failed: %m",
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->temp_prefix);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_close(&stream->istream);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return -1;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen i_stream_sync(sstream->fd_input);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_skip(sstream->cur_input, size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->write_peak += size;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_seek(sstream->fd_input, stream->istream.v_offset);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ret = i_stream_read(sstream->fd_input);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (ret <= 0) {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen stream->istream.eof = sstream->fd_input->eof;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen stream->istream.stream_errno =
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->fd_input->stream_errno;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen stream->buffer = i_stream_get_data(sstream->fd_input, &pos);
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen stream->pos -= stream->skip;
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen stream->skip = 0;
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen
4da70fe8c9cb6e57b36103d78ab1e9c8654f76d9Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : ret;
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen stream->pos = pos;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen return ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void _seek(struct istream_private *stream, uoff_t v_offset,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen bool mark ATTR_UNUSED)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
8d235b34022f0bf0f7db54fdbda2d4fd204ed864Timo Sirainen stream->istream.stream_errno = 0;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen stream->istream.v_offset = v_offset;
8d235b34022f0bf0f7db54fdbda2d4fd204ed864Timo Sirainen stream->skip = stream->pos = 0;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic const struct stat *_stat(struct istream_private *stream, bool exact)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream = (struct seekable_istream *)stream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen uoff_t old_offset;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen ssize_t ret;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen if (sstream->buffer != NULL) {
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen /* we want to know the full size of the file, so read until
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen we're finished */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen old_offset = stream->istream.v_offset;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen do {
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_skip(&stream->istream, stream->skip);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen } while ((ret = _read(stream)) > 0);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen if (ret == 0) {
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen i_panic("i_stream_stat() used for non-blocking "
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen "seekable stream");
7efee0bb408b0d5253e41997857bdda57855cdc7Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_seek(&stream->istream, old_offset);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen if (sstream->fd_input != NULL) {
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen /* using a file backed buffer, we can use real fstat() */
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen return i_stream_stat(sstream->fd_input, exact);
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen } else {
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen /* buffer is completely in memory */
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen i_assert(sstream->buffer != NULL);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen stream->statbuf.st_size = sstream->buffer->used;
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen return &stream->statbuf;
8255a22cccf3b0ccf38206c594941820ac1c9e00Timo Sirainen }
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainenstruct istream *
fe363b433b8038a69b55169da9dca27892ad7d18Timo Siraineni_stream_create_seekable(struct istream *input[],
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen size_t max_buffer_size, const char *temp_prefix)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen{
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen struct seekable_istream *sstream;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen const unsigned char *data;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen unsigned int count;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen size_t size;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen for (count = 0; input[count] != NULL; count++)
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_ref(input[count]);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_assert(count != 0);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen sstream = i_new(struct seekable_istream, 1);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen sstream->temp_prefix = i_strdup(temp_prefix);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen sstream->buffer = buffer_create_dynamic(default_pool, BUF_INITIAL_SIZE);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->max_buffer_size = max_buffer_size;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen sstream->input = i_new(struct istream *, count + 1);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen memcpy(sstream->input, input, sizeof(*input) * count);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->cur_input = sstream->input[0];
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen /* initialize our buffer from first stream's pending data */
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen data = i_stream_get_data(sstream->cur_input, &size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen buffer_append(sstream->buffer, data, size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen i_stream_skip(sstream->cur_input, size);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.iostream.close = _close;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.iostream.destroy = _destroy;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.read = _read;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.seek = _seek;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen sstream->istream.stat = _stat;
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return i_stream_create(&sstream->istream, -1, 0);
2201e2cc1b3f744dac61c2bf8095bcb6b5719540Timo Sirainen}