bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen#include "lib.h"
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen#include "hash-method.h"
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen#include "istream-private.h"
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen#include "istream-hash.h"
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainenstruct hash_istream {
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen struct istream_private istream;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen const struct hash_method *method;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen void *hash_context;
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen uoff_t high_offset;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen};
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainenstatic ssize_t
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Siraineni_stream_hash_read(struct istream_private *stream)
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen{
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen struct hash_istream *hstream = (struct hash_istream *)stream;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen const unsigned char *data;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen size_t size;
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen uoff_t skip;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen ssize_t ret;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset +
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen stream->istream.v_offset);
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen if (ret > 0 && hstream->hash_context != NULL) {
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen data = i_stream_get_data(&stream->istream, &size);
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen i_assert((size_t)ret <= size);
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen i_assert(stream->istream.v_offset <= hstream->high_offset);
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen skip = hstream->high_offset - stream->istream.v_offset;
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen if (skip < (size_t)size) {
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen hstream->high_offset += (size-skip);
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen hstream->method->loop(hstream->hash_context,
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen data+skip, size-skip);
202a34580f6204672d9b0d6a0756f35a3c4cdef6Timo Sirainen }
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen } else if (ret < 0) {
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen /* we finished hashing it. don't access it anymore, because
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen the memory pointed by the hash may be freed before the
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen istream itself */
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen hstream->hash_context = NULL;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen }
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen return ret;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen}
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainenstatic void
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Siraineni_stream_hash_seek(struct istream_private *stream,
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen{
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen struct hash_istream *hstream = (struct hash_istream *)stream;
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen if (hstream->hash_context != NULL) {
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen io_stream_set_error(&stream->iostream,
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen "Seeking not supported before hashing is finished");
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen stream->istream.stream_errno = ESPIPE;
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen }
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen stream->istream.v_offset = v_offset;
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen stream->skip = stream->pos = 0;
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen}
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainenstruct istream *
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Siraineni_stream_create_hash(struct istream *input, const struct hash_method *method,
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen void *hash_context)
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen{
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen struct hash_istream *hstream;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen hstream = i_new(struct hash_istream, 1);
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen hstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen hstream->istream.stream_size_passthrough = TRUE;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen hstream->istream.read = i_stream_hash_read;
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen hstream->istream.seek = i_stream_hash_seek;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
25fb397382c6f7d39bfeee85774e7675f02bfb3cTimo Sirainen hstream->istream.istream.readable_fd = input->readable_fd;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen hstream->istream.istream.blocking = input->blocking;
cbb79ea1b1a49255c6edc46409a544666b22788fTimo Sirainen hstream->istream.istream.seekable = input->seekable;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen hstream->method = method;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen hstream->hash_context = hash_context;
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen return i_stream_create(&hstream->istream, input,
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen i_stream_get_fd(input), 0);
3157f61431f19e01173e2e0d270c28af86dc97aaTimo Sirainen}