summaryrefslogtreecommitdiffstats
path: root/src/lib-fs/ostream-cmp.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
commitf7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch)
treea3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/lib-fs/ostream-cmp.c
parentInitial commit. (diff)
downloaddovecot-upstream.tar.xz
dovecot-upstream.zip
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/lib-fs/ostream-cmp.c95
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;
+}