istream-metawrap.c revision 2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync/* Copyright (c) 2007-2015 Dovecot authors, see the included COPYING file */
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync
d34409ad02ea0d28e08a6c4b089a412fdb3b4c9cvboxsync#include "lib.h"
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync#include "istream-private.h"
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync#include "istream-metawrap.h"
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsyncstruct metawrap_istream {
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync struct istream_private istream;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync metawrap_callback_t *callback;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync void *context;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync uoff_t start_offset, pending_seek;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync bool in_metadata;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync};
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsyncstatic int metadata_header_read(struct metawrap_istream *mstream)
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync{
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync char *line, *p;
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync while ((line = i_stream_read_next_line(mstream->istream.parent)) != NULL) {
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync if (*line == '\0') {
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync mstream->callback(NULL, NULL, mstream->context);
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync return 1;
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync }
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync p = strchr(line, ':');
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync if (p == NULL) {
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync io_stream_set_error(&mstream->istream.iostream,
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync "Metadata header line is missing ':'");
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync mstream->istream.istream.stream_errno = EINVAL;
a9b62afc62b28da7a1a77f34259f8013892d9664vboxsync return -1;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync }
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync *p++ = '\0';
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync mstream->callback(line, p, mstream->context);
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync }
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync if (mstream->istream.parent->eof) {
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->istream.istream.stream_errno =
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync mstream->istream.parent->stream_errno;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync mstream->istream.istream.eof = TRUE;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync return -1;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync }
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync i_assert(!mstream->istream.parent->blocking);
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync return 0;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync}
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsyncstatic ssize_t i_stream_metawrap_read(struct istream_private *stream)
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync{
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync struct metawrap_istream *mstream = (struct metawrap_istream *)stream;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync int ret;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync i_stream_seek(stream->parent, mstream->start_offset +
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync stream->istream.v_offset);
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync if (mstream->in_metadata) {
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync ret = metadata_header_read(mstream);
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync i_assert(stream->istream.v_offset == 0);
a6b9fb03568b86eb6be55f1db015eab0921f7ee0vboxsync mstream->start_offset = stream->parent->v_offset;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync if (ret <= 0)
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync return ret;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync /* this stream is kind of silently skipping over the metadata */
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync stream->abs_start_offset += mstream->start_offset;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync mstream->in_metadata = FALSE;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync if (mstream->pending_seek != 0) {
319b6c2f1a5b5420b0a7fbef89477984cec16007vboxsync i_stream_seek(&stream->istream, mstream->pending_seek);
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync return i_stream_read(&stream->istream);
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync }
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync }
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync /* after metadata header it's all just passthrough */
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync return i_stream_read_copy_from_parent(&stream->istream);
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync}
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsyncstatic void
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsynci_stream_metawrap_seek(struct istream_private *stream,
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync uoff_t v_offset, bool mark ATTR_UNUSED)
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync{
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync struct metawrap_istream *mstream = (struct metawrap_istream *)stream;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync if (!mstream->in_metadata) {
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync /* already read through metadata. we can skip directly. */
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync stream->istream.v_offset = v_offset;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync mstream->pending_seek = 0;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync } else {
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync /* we need to read through the metadata first */
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync mstream->pending_seek = v_offset;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync stream->istream.v_offset = 0;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync }
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync stream->skip = stream->pos = 0;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync}
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsyncstatic int i_stream_metawrap_stat(struct istream_private *stream, bool exact)
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync{
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync struct metawrap_istream *mstream = (struct metawrap_istream *)stream;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync const struct stat *st;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync int ret;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync if (i_stream_stat(stream->parent, exact, &st) < 0) {
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync stream->istream.stream_errno = stream->parent->stream_errno;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync return -1;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync }
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync stream->statbuf = *st;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync if (mstream->in_metadata) {
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync ret = i_stream_read(&stream->istream);
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync if (ret < 0)
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync return -1;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync if (ret == 0) {
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync stream->statbuf.st_size = -1;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync return 0;
3b0af6c6de3509194973be62078331fc930175f7vboxsync }
3b0af6c6de3509194973be62078331fc930175f7vboxsync }
3b0af6c6de3509194973be62078331fc930175f7vboxsync i_assert((uoff_t)stream->statbuf.st_size >= mstream->start_offset);
3b0af6c6de3509194973be62078331fc930175f7vboxsync stream->statbuf.st_size -= mstream->start_offset;
3b0af6c6de3509194973be62078331fc930175f7vboxsync return 0;
3b0af6c6de3509194973be62078331fc930175f7vboxsync}
3b0af6c6de3509194973be62078331fc930175f7vboxsync
3b0af6c6de3509194973be62078331fc930175f7vboxsyncstruct istream *
3b0af6c6de3509194973be62078331fc930175f7vboxsynci_stream_create_metawrap(struct istream *input,
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync metawrap_callback_t *callback, void *context)
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync{
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync struct metawrap_istream *mstream;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync
a6b9fb03568b86eb6be55f1db015eab0921f7ee0vboxsync mstream = i_new(struct metawrap_istream, 1);
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->istream.read = i_stream_metawrap_read;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->istream.seek = i_stream_metawrap_seek;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->istream.stat = input->seekable ? i_stream_metawrap_stat : NULL;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->istream.istream.readable_fd = input->readable_fd;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->istream.istream.blocking = input->blocking;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->istream.istream.seekable = input->seekable;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->in_metadata = TRUE;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync mstream->callback = callback;
cdaeb34871aa28b96c0d80b474f3c8f9805d0388vboxsync mstream->context = context;
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync return i_stream_create(&mstream->istream, input,
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync i_stream_get_fd(input));
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync}
3c4dd6a990d38eba0aad586bb42f72d2b10b682avboxsync