Coverage Report

Created: 2026-08-13 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib/istream-limit.c
Line
Count
Source
1
/* Copyright (c) Dovecot authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "istream-private.h"
5
6
struct limit_istream {
7
  struct istream_private istream;
8
9
  uoff_t v_size;
10
};
11
12
static void i_stream_limit_destroy(struct iostream_private *stream)
13
3.01k
{
14
3.01k
  struct limit_istream *lstream =
15
3.01k
    container_of(stream, struct limit_istream, istream.iostream);
16
3.01k
       uoff_t v_offset;
17
18
3.01k
       v_offset = lstream->istream.parent_start_offset +
19
3.01k
               lstream->istream.istream.v_offset;
20
3.01k
       if (lstream->istream.parent->seekable ||
21
3.01k
           v_offset > lstream->istream.parent->v_offset) {
22
               /* get to same position in parent stream */
23
3.01k
               i_stream_seek(lstream->istream.parent, v_offset);
24
3.01k
       }
25
3.01k
}
26
27
static ssize_t i_stream_limit_read(struct istream_private *stream)
28
8.85k
{
29
8.85k
  struct limit_istream *lstream =
30
8.85k
    container_of(stream, struct limit_istream, istream);
31
8.85k
  uoff_t left;
32
8.85k
  ssize_t ret;
33
8.85k
  size_t pos;
34
35
8.85k
  i_stream_seek(stream->parent, lstream->istream.parent_start_offset +
36
8.85k
          stream->istream.v_offset);
37
38
8.85k
  if (stream->istream.v_offset +
39
8.85k
      (stream->pos - stream->skip) >= lstream->v_size) {
40
5.80k
    stream->istream.eof = TRUE;
41
5.80k
    return -1;
42
5.80k
  }
43
44
3.05k
  stream->pos -= stream->skip;
45
3.05k
  stream->skip = 0;
46
47
3.05k
  stream->buffer = i_stream_get_data(stream->parent, &pos);
48
3.05k
  if (pos > stream->pos)
49
2.96k
    ret = 0;
50
85
  else do {
51
85
    ret = i_stream_read_memarea(stream->parent);
52
85
    stream->istream.stream_errno = stream->parent->stream_errno;
53
85
    stream->istream.eof = stream->parent->eof;
54
85
    stream->buffer = i_stream_get_data(stream->parent, &pos);
55
85
  } while (pos <= stream->pos && ret > 0);
56
3.05k
  if (ret == -2)
57
0
    return -2;
58
59
3.05k
  if (lstream->v_size != UOFF_T_MAX) {
60
3.05k
    left = lstream->v_size - stream->istream.v_offset;
61
3.05k
    if (pos >= left) {
62
2.90k
      pos = left;
63
2.90k
      stream->istream.eof = TRUE;
64
2.90k
    }
65
3.05k
  }
66
67
3.05k
  ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
68
3.05k
    (ret == 0 ? 0 : -1);
69
3.05k
  stream->pos = pos;
70
3.05k
  i_assert(ret != -1 || stream->istream.eof ||
71
3.05k
     stream->istream.stream_errno != 0);
72
3.05k
  return ret;
73
3.05k
}
74
75
static int
76
i_stream_limit_stat(struct istream_private *stream, bool exact)
77
0
{
78
0
  struct limit_istream *lstream =
79
0
    container_of(stream, struct limit_istream, istream);
80
0
  const struct stat *st;
81
82
0
  if (i_stream_stat(stream->parent, exact, &st) < 0) {
83
0
    stream->istream.stream_errno = stream->parent->stream_errno;
84
0
    return -1;
85
0
  }
86
87
0
  stream->statbuf = *st;
88
0
  if (lstream->v_size != UOFF_T_MAX)
89
0
    stream->statbuf.st_size = lstream->v_size;
90
0
  return 0;
91
0
}
92
93
static int i_stream_limit_get_size(struct istream_private *stream,
94
           bool exact, uoff_t *size_r)
95
0
{
96
0
  struct limit_istream *lstream =
97
0
    container_of(stream, struct limit_istream, istream);
98
0
  const struct stat *st;
99
100
0
  if (lstream->v_size != UOFF_T_MAX) {
101
0
    *size_r = lstream->v_size;
102
0
    return 1;
103
0
  }
104
105
0
  if (i_stream_stat(&stream->istream, exact, &st) < 0)
106
0
    return -1;
107
0
  if (st->st_size == -1)
108
0
    return 0;
109
110
0
  *size_r = st->st_size;
111
0
  return 1;
112
0
}
113
114
struct istream *i_stream_create_limit(struct istream *input, uoff_t v_size)
115
3.01k
{
116
3.01k
  struct limit_istream *lstream;
117
118
3.01k
  lstream = i_new(struct limit_istream, 1);
119
3.01k
  lstream->v_size = v_size;
120
3.01k
  lstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
121
122
3.01k
  lstream->istream.iostream.destroy = i_stream_limit_destroy;
123
3.01k
  lstream->istream.read = i_stream_limit_read;
124
3.01k
  lstream->istream.stat = i_stream_limit_stat;
125
3.01k
  lstream->istream.get_size = i_stream_limit_get_size;
126
127
3.01k
  lstream->istream.istream.readable_fd = input->readable_fd;
128
3.01k
  lstream->istream.istream.blocking = input->blocking;
129
3.01k
  lstream->istream.istream.seekable = input->seekable;
130
3.01k
  return i_stream_create(&lstream->istream, input,
131
3.01k
             i_stream_get_fd(input),
132
3.01k
             ISTREAM_HIDDEN_INPUTS_NONE, 0);
133
3.01k
}
134
135
struct istream *i_stream_create_range(struct istream *input,
136
              uoff_t v_offset, uoff_t v_size)
137
0
{
138
0
  uoff_t orig_offset = input->v_offset;
139
0
  struct istream *ret;
140
141
0
  input->v_offset = v_offset;
142
0
  ret = i_stream_create_limit(input, v_size);
143
0
  input->v_offset = orig_offset;
144
0
  return ret;
145
0
}