diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-fs/ostream-cmp.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/lib-fs/ostream-cmp.c b/src/lib-fs/ostream-cmp.c new file mode 100644 index 0000000..8599799 --- /dev/null +++ b/src/lib-fs/ostream-cmp.c @@ -0,0 +1,95 @@ +/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "istream.h" +#include "ostream-private.h" +#include "ostream-cmp.h" + +struct cmp_ostream { + struct ostream_private ostream; + + struct istream *input; + bool equals; +}; + +static void o_stream_cmp_close(struct iostream_private *stream, + bool close_parent) +{ + struct cmp_ostream *cstream = (struct cmp_ostream *)stream; + + if (cstream->input == NULL) + return; + + i_stream_unref(&cstream->input); + if (close_parent) + o_stream_close(cstream->ostream.parent); +} + +bool stream_cmp_block(struct istream *input, + const unsigned char *data, size_t size) +{ + const unsigned char *indata; + size_t insize, max; + + while (size > 0) { + (void)i_stream_read_bytes(input, &indata, &insize, size); + max = I_MIN(insize, size); + if (insize == 0 || memcmp(data, indata, max) != 0) + return FALSE; + data += max; + size -= max; + i_stream_skip(input, max); + } + return TRUE; +} + +static ssize_t +o_stream_cmp_sendv(struct ostream_private *stream, + const struct const_iovec *iov, unsigned int iov_count) +{ + struct cmp_ostream *cstream = (struct cmp_ostream *)stream; + unsigned int i; + ssize_t ret; + + if (cstream->equals) { + for (i = 0; i < iov_count; i++) { + if (!stream_cmp_block(cstream->input, iov[i].iov_base, + iov[i].iov_len)) { + cstream->equals = FALSE; + break; + } + } + } + + if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) { + o_stream_copy_error_from_parent(stream); + return -1; + } + + stream->ostream.offset += ret; + return ret; +} + +struct ostream * +o_stream_create_cmp(struct ostream *output, struct istream *input) +{ + struct cmp_ostream *cstream; + + cstream = i_new(struct cmp_ostream, 1); + cstream->ostream.sendv = o_stream_cmp_sendv; + cstream->ostream.iostream.close = o_stream_cmp_close; + cstream->input = input; + cstream->equals = TRUE; + i_stream_ref(input); + + return o_stream_create(&cstream->ostream, output, + o_stream_get_fd(output)); +} + +bool o_stream_cmp_equals(struct ostream *_output) +{ + struct cmp_ostream *cstream = + (struct cmp_ostream *)_output->real_stream; + + return cstream->equals; +} |