Coverage Report

Created: 2026-10-28 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-fs/ostream-cmp.c
Line
Count
Source
1
/* Copyright (c) Dovecot authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "istream.h"
5
#include "ostream-private.h"
6
#include "ostream-cmp.h"
7
8
struct cmp_ostream {
9
  struct ostream_private ostream;
10
11
  struct istream *input;
12
  bool equals;
13
};
14
15
static void o_stream_cmp_close(struct iostream_private *stream,
16
             bool close_parent)
17
0
{
18
0
  struct cmp_ostream *cstream = (struct cmp_ostream *)stream;
19
20
0
  if (cstream->input == NULL)
21
0
    return;
22
23
0
  i_stream_unref(&cstream->input);
24
0
  if (close_parent)
25
0
    o_stream_close(cstream->ostream.parent);
26
0
}
27
28
bool stream_cmp_block(struct istream *input,
29
          const unsigned char *data, size_t size)
30
0
{
31
0
  const unsigned char *indata;
32
0
  size_t insize, max;
33
34
0
  while (size > 0) {
35
0
    (void)i_stream_read_bytes(input, &indata, &insize, size);
36
0
    max = I_MIN(insize, size);
37
0
    if (insize == 0 || memcmp(data, indata, max) != 0)
38
0
      return FALSE;
39
0
    data += max;
40
0
    size -= max;
41
0
    i_stream_skip(input, max);
42
0
  }
43
0
  return TRUE;
44
0
}
45
46
static ssize_t
47
o_stream_cmp_sendv(struct ostream_private *stream,
48
       const struct const_iovec *iov, unsigned int iov_count)
49
0
{
50
0
  struct cmp_ostream *cstream = (struct cmp_ostream *)stream;
51
0
  unsigned int i;
52
0
  ssize_t ret;
53
54
0
  if (cstream->equals) {
55
0
    for (i = 0; i < iov_count; i++) {
56
0
      if (!stream_cmp_block(cstream->input, iov[i].iov_base,
57
0
                iov[i].iov_len)) {
58
0
        cstream->equals = FALSE;
59
0
        break;
60
0
      }
61
0
    }
62
0
  }
63
64
0
  if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
65
0
    o_stream_copy_error_from_parent(stream);
66
0
    return -1;
67
0
  }
68
69
0
  stream->ostream.offset += ret;
70
0
  return ret;
71
0
}
72
73
struct ostream *
74
o_stream_create_cmp(struct ostream *output, struct istream *input)
75
0
{
76
0
  struct cmp_ostream *cstream;
77
78
0
  cstream = i_new(struct cmp_ostream, 1);
79
0
  cstream->ostream.sendv = o_stream_cmp_sendv;
80
0
  cstream->ostream.iostream.close = o_stream_cmp_close;
81
0
  cstream->input = input;
82
0
  cstream->equals = TRUE;
83
0
  i_stream_ref(input);
84
85
0
  return o_stream_create(&cstream->ostream, output,
86
0
             o_stream_get_fd(output));
87
0
}
88
89
bool o_stream_cmp_equals(struct ostream *_output)
90
0
{
91
0
  struct cmp_ostream *cstream =
92
0
    (struct cmp_ostream *)_output->real_stream;
93
94
0
  return cstream->equals;
95
0
}