istream-hash.c revision 25fb397382c6f7d39bfeee85774e7675f02bfb3c
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen/* Copyright (c) 2013-2015 Dovecot authors, see the included COPYING file */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "lib.h"
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen#include "hash-method.h"
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen#include "istream-private.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "istream-hash.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
22535a9e685e29214082878e37a267157044618eTimo Sirainenstruct hash_istream {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct istream_private istream;
1f1e81aab38d833d1c9cdc244c91fd762e0080d4Timo Sirainen
1f1e81aab38d833d1c9cdc244c91fd762e0080d4Timo Sirainen const struct hash_method *method;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen void *hash_context;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen uoff_t high_offset;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen};
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainenstatic ssize_t
25757faf029c369a8318349dafe952e2358df1d8Timo Siraineni_stream_hash_read(struct istream_private *stream)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen{
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct hash_istream *hstream = (struct hash_istream *)stream;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen const unsigned char *data;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen size_t size;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen uoff_t skip;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen ssize_t ret;
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset +
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen stream->istream.v_offset);
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen if (ret > 0 && hstream->hash_context != NULL) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen data = i_stream_get_data(&stream->istream, &size);
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen i_assert((size_t)ret <= size);
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen i_assert(stream->istream.v_offset <= hstream->high_offset);
skip = hstream->high_offset - stream->istream.v_offset;
if (skip < (size_t)size) {
hstream->high_offset += (size-skip);
hstream->method->loop(hstream->hash_context,
data+skip, size-skip);
}
} else if (ret < 0) {
/* we finished hashing it. don't access it anymore, because
the memory pointed by the hash may be freed before the
istream itself */
hstream->hash_context = NULL;
}
return ret;
}
static void
i_stream_hash_seek(struct istream_private *stream,
uoff_t v_offset, bool mark ATTR_UNUSED)
{
struct hash_istream *hstream = (struct hash_istream *)stream;
if (hstream->hash_context != NULL) {
io_stream_set_error(&stream->iostream,
"Seeking not supported before hashing is finished");
stream->istream.stream_errno = ESPIPE;
}
stream->istream.v_offset = v_offset;
stream->skip = stream->pos = 0;
}
struct istream *
i_stream_create_hash(struct istream *input, const struct hash_method *method,
void *hash_context)
{
struct hash_istream *hstream;
hstream = i_new(struct hash_istream, 1);
hstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
hstream->istream.stream_size_passthrough = TRUE;
hstream->istream.read = i_stream_hash_read;
hstream->istream.seek = i_stream_hash_seek;
hstream->istream.istream.readable_fd = input->readable_fd;
hstream->istream.istream.blocking = input->blocking;
hstream->istream.istream.seekable = input->seekable;
hstream->method = method;
hstream->hash_context = hash_context;
return i_stream_create(&hstream->istream, input,
i_stream_get_fd(input));
}