Coverage Report

Created: 2025-08-26 07:01

/src/dovecot/src/lib/istream.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef ISTREAM_H
2
#define ISTREAM_H
3
4
/* Note that some systems (Solaris) may use a macro to redefine struct stat */
5
#include <sys/stat.h>
6
7
struct ioloop;
8
struct iostream_fd;
9
10
struct istream {
11
  uoff_t v_offset;
12
13
  /* Commonly used errors:
14
15
     ENOENT  - File/object doesn't exist.
16
     EPIPE   - Stream ended unexpectedly (or i_stream_close() was called).
17
     ESPIPE  - i_stream_seek() was used on a stream that can't be seeked.
18
     ENOBUFS - i_stream_read_next_line() was used for a too long line.
19
     EIO     - Internal error. Retrying may work, but it may also be
20
               because of a misconfiguration.
21
     EINVAL  - Stream is corrupted.
22
23
     If stream_errno != 0, eof==TRUE as well.
24
  */
25
  int stream_errno;
26
27
  bool mmaped:1; /* be careful when copying data */
28
  bool blocking:1; /* read() shouldn't return 0 */
29
  bool closed:1;
30
  bool readable_fd:1; /* fd can be read directly if necessary
31
                                 (for sendfile()) */
32
  bool seekable:1; /* we can seek() backwards */
33
  /* read() has reached to end of file (but there may still be data
34
     available in buffer) or stream_errno != 0 */
35
  bool eof:1;
36
37
  struct istream_private *real_stream;
38
};
39
40
typedef void istream_callback_t(void *context);
41
42
struct istream *i_stream_create_fd(int fd, size_t max_buffer_size);
43
/* The fd is set to -1 immediately to avoid accidentally closing it twice. */
44
struct istream *i_stream_create_fd_autoclose(int *fd, size_t max_buffer_size);
45
/* Autoclose the fd once ref's refcount drops to 0. This function increases the
46
   refcount, so the caller is expected to unref it as well. */
47
struct istream *i_stream_create_fd_ref_autoclose(struct iostream_fd *ref,
48
             size_t max_buffer_size);
49
/* Open the given path only when something is actually tried to be read from
50
   the stream. */
51
struct istream *i_stream_create_file(const char *path, size_t max_buffer_size);
52
/* Create an input stream using the provided data block. That data block must
53
remain allocated during the full lifetime of the stream. */
54
struct istream *i_stream_create_from_data(const void *data, size_t size);
55
#define i_stream_create_from_buffer(buf) \
56
  i_stream_create_from_data((buf)->data, (buf)->used)
57
#define i_stream_create_from_string(str) \
58
  i_stream_create_from_data(str_data(str), str_len(str))
59
/* Create an input stream using a copy of the provided data block. The
60
   provided data block may be freed at any time. The copy is freed when the
61
   stream is destroyed. */
62
struct istream *
63
i_stream_create_copy_from_data(const void *data, size_t size);
64
#define i_stream_create_copy_from_buffer(buf) \
65
  i_stream_create_copy_from_data((buf)->data, (buf)->used)
66
#define i_stream_create_copy_from_string(str) \
67
  i_stream_create_copy_from_data(str_data(str), str_len(str))
68
/* Create a no-operation wrapper to allow input to be used as child stream. */
69
struct istream *i_stream_create_noop(struct istream *input);
70
struct istream *i_stream_create_limit(struct istream *input, uoff_t v_size);
71
struct istream *i_stream_create_range(struct istream *input,
72
              uoff_t v_offset, uoff_t v_size);
73
struct istream *i_stream_create_error(int stream_errno);
74
struct istream *
75
i_stream_create_error_str(int stream_errno, const char *fmt, ...)
76
  ATTR_FORMAT(2, 3);
77
78
/* Set name (e.g. path) for input stream. */
79
void i_stream_set_name(struct istream *stream, const char *name);
80
/* Get input stream's name. If stream itself doesn't have a name,
81
   it looks up further into stream's parents until one of them has a name.
82
   Returns "" if stream has no name. */
83
const char *i_stream_get_name(struct istream *stream);
84
85
/* Close this stream (but not its parents) and unreference it. */
86
void i_stream_destroy(struct istream **stream);
87
88
/* Reference counting. References start from 1, so calling i_stream_unref()
89
   destroys the stream if i_stream_ref() is never used. */
90
void i_stream_ref(struct istream *stream);
91
/* Unreferences the stream and sets stream pointer to NULL. */
92
void i_stream_unref(struct istream **stream);
93
/* Call the given callback function when stream is destroyed. */
94
void i_stream_add_destroy_callback(struct istream *stream,
95
           istream_callback_t *callback, void *context)
96
  ATTR_NULL(3);
97
#define i_stream_add_destroy_callback(stream, callback, context) \
98
0
  i_stream_add_destroy_callback(stream - \
99
0
    CALLBACK_TYPECHECK(callback, void (*)(typeof(context))), \
100
0
    (istream_callback_t *)callback, context)
101
/* Remove the destroy callback. */
102
void i_stream_remove_destroy_callback(struct istream *stream,
103
              void (*callback)());
104
105
/* Return file descriptor for stream, or -1 if none is available. */
106
int i_stream_get_fd(struct istream *stream);
107
/* Copy the file descriptor from source istream to destination istream.
108
   The readable_fd is preserved. Assert-crashes if source doesn't have a
109
   file descriptor. */
110
void i_stream_copy_fd(struct istream *dest, struct istream *source);
111
/* Set error for istream. */
112
void i_stream_set_error(struct istream *stream, int stream_errno,
113
      const char *fmt, ...) ATTR_FORMAT(3, 4);
114
/* Returns error string for the last error. It also returns "EOF" in case there
115
   is no error, but eof is set. Otherwise it returns "<no error>". */
116
const char *i_stream_get_error(struct istream *stream);
117
/* Returns human-readable reason for why istream was disconnected.
118
   The output is either "Connection closed" for clean disconnections or
119
   "Connection closed: <error>" for unclean disconnections. This is an
120
   alternative to i_stream_get_error(), which is preferred to be used when
121
   logging errors about client connections. */
122
const char *i_stream_get_disconnect_reason(struct istream *stream);
123
124
/* Mark the stream and all of its parent streams closed. Any reads after this
125
   will return -1. The data already read can still be used. */
126
void i_stream_close(struct istream *stream);
127
/* Sync the stream with the underlying backend, ie. if a file has been
128
   modified, flush any cached data. */
129
void i_stream_sync(struct istream *stream);
130
131
/* Change the initial size for stream's input buffer. This basically just
132
   grows the read buffer size from the default. This function has no effect
133
   unless it's called before reading anything. */
134
void i_stream_set_init_buffer_size(struct istream *stream, size_t size);
135
/* Change the maximum size for stream's input buffer to grow. Useful only
136
   for buffered streams (currently only file). This changes also all the
137
   parent streams' max buffer size. */
138
void i_stream_set_max_buffer_size(struct istream *stream, size_t max_size);
139
/* Returns the current max. buffer size for the stream. This function also
140
   goes through all of the parent streams and returns the highest seen max
141
   buffer size. This is needed because some streams (e.g. istream-chain) change
142
   their max buffer size dynamically. */
143
size_t i_stream_get_max_buffer_size(struct istream *stream);
144
/* Enable/disable i_stream[_read]_next_line() returning the last line if it
145
   doesn't end with LF. */
146
void i_stream_set_return_partial_line(struct istream *stream, bool set);
147
/* Change whether buffers are allocated persistently (default=TRUE). When not,
148
   the memory usage is minimized by freeing the stream's buffers whenever they
149
   become empty. */
150
void i_stream_set_persistent_buffers(struct istream *stream, bool set);
151
/* Set the istream blocking or nonblocking, including its parent streams.
152
   If any of the istreams have an fd, its O_NONBLOCK flag is changed. */
153
void i_stream_set_blocking(struct istream *stream, bool blocking);
154
155
/* Returns number of bytes read if read was ok, 0 if stream is non-blocking and
156
   no more data is available, -1 if EOF or error, -2 if the input buffer is
157
   full. If <=0 is returned, pointers to existing data returned by the previous
158
   i_stream_get_data() will stay valid, although calling it again may return
159
   a different pointer. The pointers to old data are invalidated again when
160
   return value is >0. */
161
ssize_t i_stream_read(struct istream *stream);
162
/* Skip forward a number of bytes. Never fails, the next read tells if it
163
   was successful. */
164
void i_stream_skip(struct istream *stream, uoff_t count);
165
/* Seek to specified position from beginning of file. Never fails, the next
166
   read tells if it was successful. This works only for files, others will
167
   set stream_errno=ESPIPE. */
168
void i_stream_seek(struct istream *stream, uoff_t v_offset);
169
/* Like i_stream_seek(), but also giving a hint that after reading some data
170
   we could be seeking back to this mark or somewhere after it. If input
171
   stream's implementation is slow in seeking backwards, it can use this hint
172
   to cache some of the data in memory. */
173
void i_stream_seek_mark(struct istream *stream, uoff_t v_offset);
174
/* Returns 0 if ok, -1 if error. As the underlying stream may not be
175
   a file, only some of the fields might be set, others would be zero.
176
   st_size is always set, and if it's not known, it's -1.
177
178
   If exact=FALSE, the stream may not return exactly correct values, but the
179
   returned values can be compared to see if anything had changed (eg. in
180
   compressed stream st_size could be compressed size) */
181
int i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r);
182
/* Similar to i_stream_stat() call. Returns 1 if size was successfully
183
   set, 0 if size is unknown, -1 if error. */
184
int i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r);
185
/* Returns TRUE if there are any bytes left to be read or in buffer. */
186
bool i_stream_have_bytes_left(struct istream *stream);
187
/* Returns TRUE if there are no bytes currently buffered and i_stream_read()
188
   returns EOF/error. Usually it's enough to check for stream->eof instead of
189
   calling this function. Note that if the stream isn't at EOF, this function
190
   has now read data into the stream buffer. */
191
bool i_stream_read_eof(struct istream *stream);
192
/* Returns the absolute offset of the stream. This is the stream's current
193
   v_offset + the parent's absolute offset when the stream was created. */
194
uoff_t i_stream_get_absolute_offset(struct istream *stream);
195
196
/* Gets the next line from stream and returns it, or NULL if more data is
197
   needed to make a full line. i_stream_set_return_partial_line() specifies
198
   if the last line should be returned if it doesn't end with LF. */
199
char *i_stream_next_line(struct istream *stream);
200
/* Like i_stream_next_line(), but reads for more data if needed. Returns NULL
201
   if more data is needed or error occurred. If the input buffer gets full,
202
   stream_errno is set to ENOBUFS. */
203
char *i_stream_read_next_line(struct istream *stream);
204
/* Returns TRUE if the last line read with i_stream_next_line() ended with
205
   CRLF (instead of LF). */
206
bool i_stream_last_line_crlf(struct istream *stream);
207
208
/* Returns pointer to beginning of read data. */
209
const unsigned char *i_stream_get_data(struct istream *stream, size_t *size_r);
210
size_t i_stream_get_data_size(struct istream *stream);
211
/* Like i_stream_get_data(), but returns non-const data. This only works with
212
   buffered streams (currently only file), others return NULL. */
213
unsigned char *i_stream_get_modifiable_data(struct istream *stream,
214
              size_t *size_r);
215
/* Like i_stream_get_data(), but read more when needed. Returns 1 if more
216
   than threshold bytes are available, 0 if as much or less, -1 if error or
217
   EOF with no bytes read that weren't already in buffer, or -2 if stream's
218
   input buffer is full. */
219
int i_stream_read_data(struct istream *stream, const unsigned char **data_r,
220
           size_t *size_r, size_t threshold);
221
/* Like i_stream_get_data(), but read more when needed. Returns 1 if at least
222
   the wanted number of bytes are available, 0 if less, -1 if error or
223
   EOF with no bytes read that weren't already in buffer, or -2 if stream's
224
   input buffer is full. */
225
static inline int
226
i_stream_read_bytes(struct istream *stream, const unsigned char **data_r,
227
      size_t *size_r, size_t wanted)
228
13.4k
{
229
13.4k
  i_assert(wanted > 0);
230
13.4k
  return i_stream_read_data(stream, data_r, size_r, wanted - 1);
231
13.4k
}
Unexecuted instantiation: fuzz-smtp-server.c:i_stream_read_bytes
Unexecuted instantiation: smtp-server-cmd-data.c:i_stream_read_bytes
Unexecuted instantiation: smtp-server-reply.c:i_stream_read_bytes
Unexecuted instantiation: smtp-server-connection.c:i_stream_read_bytes
Unexecuted instantiation: smtp-server.c:i_stream_read_bytes
Unexecuted instantiation: smtp-reply-parser.c:i_stream_read_bytes
Unexecuted instantiation: smtp-command-parser.c:i_stream_read_bytes
Unexecuted instantiation: smtp-server-cmd-starttls.c:i_stream_read_bytes
Unexecuted instantiation: smtp-server-cmd-auth.c:i_stream_read_bytes
Unexecuted instantiation: smtp-server-cmd-xclient.c:i_stream_read_bytes
Unexecuted instantiation: istream-dot.c:i_stream_read_bytes
Unexecuted instantiation: fuzzer.c:i_stream_read_bytes
Unexecuted instantiation: connection.c:i_stream_read_bytes
Unexecuted instantiation: iostream.c:i_stream_read_bytes
Unexecuted instantiation: iostream-pump.c:i_stream_read_bytes
Unexecuted instantiation: iostream-rawlog.c:i_stream_read_bytes
Unexecuted instantiation: istream.c:i_stream_read_bytes
Unexecuted instantiation: istream-chain.c:i_stream_read_bytes
Unexecuted instantiation: istream-data.c:i_stream_read_bytes
Unexecuted instantiation: istream-failure-at.c:i_stream_read_bytes
Unexecuted instantiation: istream-file.c:i_stream_read_bytes
Unexecuted instantiation: istream-limit.c:i_stream_read_bytes
Unexecuted instantiation: istream-rawlog.c:i_stream_read_bytes
Unexecuted instantiation: istream-sized.c:i_stream_read_bytes
Unexecuted instantiation: istream-unix.c:i_stream_read_bytes
Unexecuted instantiation: ioloop.c:i_stream_read_bytes
ostream.c:i_stream_read_bytes
Line
Count
Source
228
13.4k
{
229
13.4k
  i_assert(wanted > 0);
230
13.4k
  return i_stream_read_data(stream, data_r, size_r, wanted - 1);
231
13.4k
}
Unexecuted instantiation: ostream-file.c:i_stream_read_bytes
232
/* Short-hand for just requesting more data (i.e. even one byte) */
233
static inline int
234
i_stream_read_more(struct istream *stream, const unsigned char **data_r,
235
       size_t *size_r)
236
13.4k
{
237
13.4k
  int ret = i_stream_read_bytes(stream, data_r, size_r, 1);
238
13.4k
  i_assert(ret != -2); /* stream must have space for at least 1 byte */
239
13.4k
  return ret;
240
13.4k
}
Unexecuted instantiation: fuzz-smtp-server.c:i_stream_read_more
Unexecuted instantiation: smtp-server-cmd-data.c:i_stream_read_more
Unexecuted instantiation: smtp-server-reply.c:i_stream_read_more
Unexecuted instantiation: smtp-server-connection.c:i_stream_read_more
Unexecuted instantiation: smtp-server.c:i_stream_read_more
Unexecuted instantiation: smtp-reply-parser.c:i_stream_read_more
Unexecuted instantiation: smtp-command-parser.c:i_stream_read_more
Unexecuted instantiation: smtp-server-cmd-starttls.c:i_stream_read_more
Unexecuted instantiation: smtp-server-cmd-auth.c:i_stream_read_more
Unexecuted instantiation: smtp-server-cmd-xclient.c:i_stream_read_more
Unexecuted instantiation: istream-dot.c:i_stream_read_more
Unexecuted instantiation: fuzzer.c:i_stream_read_more
Unexecuted instantiation: connection.c:i_stream_read_more
Unexecuted instantiation: iostream.c:i_stream_read_more
Unexecuted instantiation: iostream-pump.c:i_stream_read_more
Unexecuted instantiation: iostream-rawlog.c:i_stream_read_more
Unexecuted instantiation: istream.c:i_stream_read_more
Unexecuted instantiation: istream-chain.c:i_stream_read_more
Unexecuted instantiation: istream-data.c:i_stream_read_more
Unexecuted instantiation: istream-failure-at.c:i_stream_read_more
Unexecuted instantiation: istream-file.c:i_stream_read_more
Unexecuted instantiation: istream-limit.c:i_stream_read_more
Unexecuted instantiation: istream-rawlog.c:i_stream_read_more
Unexecuted instantiation: istream-sized.c:i_stream_read_more
Unexecuted instantiation: istream-unix.c:i_stream_read_more
Unexecuted instantiation: ioloop.c:i_stream_read_more
ostream.c:i_stream_read_more
Line
Count
Source
236
13.4k
{
237
13.4k
  int ret = i_stream_read_bytes(stream, data_r, size_r, 1);
238
13.4k
  i_assert(ret != -2); /* stream must have space for at least 1 byte */
239
13.4k
  return ret;
240
13.4k
}
Unexecuted instantiation: ostream-file.c:i_stream_read_more
241
/* Like i_stream_read_more(), but tries to avoid buffering more than the
242
   indicated limit. Use this function to prevent growing the stream buffer
243
   beyond what the application is willing to read immediately. Since this
244
   function doesn't fully prevent buffering beyond the limit, the amount of data
245
   actually buffered can exceed the limit. However, *size_r will always be <=
246
   limit to avoid confusion. */
247
int i_stream_read_limited(struct istream *stream, const unsigned char **data_r,
248
        size_t *size_r, size_t limit);
249
/* Return the timestamp when istream last successfully read something.
250
   The timestamp is 0 if nothing has ever been read. */
251
void i_stream_get_last_read_time(struct istream *stream, struct timeval *tv_r);
252
253
/* Append external data to input stream. Returns TRUE if successful, FALSE if
254
   there is not enough space in the stream. */
255
bool i_stream_add_data(struct istream *stream, const unsigned char *data,
256
           size_t size);
257
258
void i_stream_set_input_pending(struct istream *stream, bool pending);
259
260
/* If there are any I/O loop items associated with the stream, move all of
261
   them to provided/current ioloop. */
262
void i_stream_switch_ioloop_to(struct istream *stream, struct ioloop *ioloop);
263
void i_stream_switch_ioloop(struct istream *stream);
264
265
#endif