/src/dovecot/src/lib/istream.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "ioloop.h" |
5 | | #include "array.h" |
6 | | #include "str.h" |
7 | | #include "memarea.h" |
8 | | #include "istream-private.h" |
9 | | |
10 | | static bool i_stream_is_buffer_invalid(const struct istream_private *stream); |
11 | | |
12 | | void i_stream_set_name(struct istream *stream, const char *name) |
13 | 1.94k | { |
14 | 1.94k | i_free(stream->real_stream->iostream.name); |
15 | 1.94k | stream->real_stream->iostream.name = i_strdup(name); |
16 | 1.94k | } |
17 | | |
18 | | const char *i_stream_get_name(struct istream *stream) |
19 | 933 | { |
20 | 933 | i_assert(stream != NULL); |
21 | 933 | while (stream->real_stream->iostream.name == NULL) { |
22 | 0 | stream = stream->real_stream->parent; |
23 | 0 | if (stream == NULL) |
24 | 0 | return ""; |
25 | 0 | } |
26 | 933 | return stream->real_stream->iostream.name; |
27 | 933 | } |
28 | | |
29 | | static void i_stream_close_full(struct istream *stream, bool close_parents) |
30 | 933 | { |
31 | 933 | io_stream_close(&stream->real_stream->iostream, close_parents); |
32 | 933 | stream->closed = TRUE; |
33 | | |
34 | 933 | if (stream->stream_errno == 0) |
35 | 592 | stream->stream_errno = EPIPE; |
36 | 933 | } |
37 | | |
38 | | void i_stream_destroy(struct istream **stream) |
39 | 1.01k | { |
40 | 1.01k | if (*stream == NULL) |
41 | 80 | return; |
42 | | |
43 | 933 | i_stream_close_full(*stream, FALSE); |
44 | 933 | i_stream_unref(stream); |
45 | 933 | } |
46 | | |
47 | | void i_stream_ref(struct istream *stream) |
48 | 1.94k | { |
49 | 1.94k | io_stream_ref(&stream->real_stream->iostream); |
50 | 1.94k | } |
51 | | |
52 | | void i_stream_unref(struct istream **_stream) |
53 | 9.81k | { |
54 | 9.81k | struct istream *stream = *_stream; |
55 | 9.81k | struct istream_private *rstream; |
56 | | |
57 | 9.81k | if (stream == NULL) |
58 | 4.90k | return; |
59 | | |
60 | 4.90k | *_stream = NULL; |
61 | 4.90k | rstream = stream->real_stream; |
62 | | |
63 | 4.90k | if (rstream->iostream.refcount > 1) { |
64 | 1.94k | if (!io_stream_unref(&rstream->iostream)) |
65 | 0 | i_unreached(); |
66 | 2.95k | } else { |
67 | | /* The snapshot may contain pointers to the parent istreams. |
68 | | Free it before io_stream_unref() frees the parents. */ |
69 | 2.95k | i_stream_snapshot_free(&rstream->prev_snapshot); |
70 | | |
71 | 2.95k | if (io_stream_unref(&rstream->iostream)) |
72 | 0 | i_unreached(); |
73 | 2.95k | str_free(&rstream->line_str); |
74 | 2.95k | i_stream_unref(&rstream->parent); |
75 | 2.95k | io_stream_free(&rstream->iostream); |
76 | 2.95k | } |
77 | 4.90k | } |
78 | | |
79 | | #undef i_stream_add_destroy_callback |
80 | | void i_stream_add_destroy_callback(struct istream *stream, |
81 | | istream_callback_t *callback, void *context) |
82 | 0 | { |
83 | 0 | io_stream_add_destroy_callback(&stream->real_stream->iostream, |
84 | 0 | callback, context); |
85 | 0 | } |
86 | | |
87 | | void i_stream_remove_destroy_callback(struct istream *stream, |
88 | | void (*callback)()) |
89 | 0 | { |
90 | 0 | io_stream_remove_destroy_callback(&stream->real_stream->iostream, |
91 | 0 | callback); |
92 | 0 | } |
93 | | |
94 | | int i_stream_get_fd(struct istream *stream) |
95 | 1.94k | { |
96 | 1.94k | struct istream_private *_stream = stream->real_stream; |
97 | | |
98 | 1.94k | return _stream->fd; |
99 | 1.94k | } |
100 | | |
101 | | void i_stream_copy_fd(struct istream *dest, struct istream *source) |
102 | 0 | { |
103 | 0 | int fd = i_stream_get_fd(source); |
104 | |
|
105 | 0 | i_assert(fd != -1); |
106 | 0 | i_assert(dest->real_stream->fd == -1); |
107 | 0 | dest->real_stream->fd = fd; |
108 | 0 | dest->readable_fd = source->readable_fd; |
109 | 0 | } |
110 | | |
111 | | void i_stream_set_error(struct istream *stream, int stream_errno, |
112 | | const char *fmt, ...) |
113 | 0 | { |
114 | 0 | va_list args; |
115 | |
|
116 | 0 | va_start(args, fmt); |
117 | 0 | stream->stream_errno = stream_errno; |
118 | 0 | io_stream_set_verror(&stream->real_stream->iostream, fmt, args); |
119 | 0 | va_end(args); |
120 | 0 | } |
121 | | |
122 | | const char *i_stream_get_error(struct istream *stream) |
123 | 341 | { |
124 | 341 | struct istream *s; |
125 | | |
126 | | /* we'll only return errors for streams that have stream_errno set or |
127 | | that have reached EOF. we might be returning unintended error |
128 | | otherwise. */ |
129 | 341 | if (stream->stream_errno == 0) |
130 | 0 | return stream->eof ? "EOF" : "<no error>"; |
131 | | |
132 | 341 | for (s = stream; s != NULL; s = s->real_stream->parent) { |
133 | 341 | if (s->stream_errno == 0) |
134 | 0 | break; |
135 | 341 | if (s->real_stream->iostream.error != NULL) |
136 | 341 | return s->real_stream->iostream.error; |
137 | 341 | } |
138 | 0 | return strerror(stream->stream_errno); |
139 | 341 | } |
140 | | |
141 | | const char *i_stream_get_disconnect_reason(struct istream *stream) |
142 | 0 | { |
143 | 0 | return io_stream_get_disconnect_reason(stream, NULL); |
144 | 0 | } |
145 | | |
146 | | void i_stream_close(struct istream *stream) |
147 | 0 | { |
148 | 0 | if (stream != NULL) |
149 | 0 | i_stream_close_full(stream, TRUE); |
150 | 0 | } |
151 | | |
152 | | void i_stream_set_init_buffer_size(struct istream *stream, size_t size) |
153 | 0 | { |
154 | 0 | stream->real_stream->init_buffer_size = size; |
155 | 0 | } |
156 | | |
157 | | void i_stream_set_max_buffer_size(struct istream *stream, size_t max_size) |
158 | 933 | { |
159 | 933 | io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size); |
160 | 933 | } |
161 | | |
162 | | size_t i_stream_get_max_buffer_size(struct istream *stream) |
163 | 1.78k | { |
164 | 1.78k | size_t max_size = 0; |
165 | | |
166 | 1.78k | do { |
167 | 1.78k | if (max_size < stream->real_stream->max_buffer_size) |
168 | 1.78k | max_size = stream->real_stream->max_buffer_size; |
169 | 1.78k | stream = stream->real_stream->parent; |
170 | 1.78k | } while (stream != NULL); |
171 | 1.78k | return max_size; |
172 | 1.78k | } |
173 | | |
174 | | void i_stream_set_return_partial_line(struct istream *stream, bool set) |
175 | 0 | { |
176 | 0 | stream->real_stream->return_nolf_line = set; |
177 | 0 | } |
178 | | |
179 | | void i_stream_set_persistent_buffers(struct istream *stream, bool set) |
180 | 0 | { |
181 | 0 | do { |
182 | 0 | stream->real_stream->nonpersistent_buffers = !set; |
183 | 0 | stream = stream->real_stream->parent; |
184 | 0 | } while (stream != NULL); |
185 | 0 | } |
186 | | |
187 | | void i_stream_set_blocking(struct istream *stream, bool blocking) |
188 | 0 | { |
189 | 0 | int prev_fd = -1; |
190 | |
|
191 | 0 | do { |
192 | 0 | stream->blocking = blocking; |
193 | 0 | if (stream->real_stream->fd != -1 && |
194 | 0 | stream->real_stream->fd != prev_fd) { |
195 | 0 | fd_set_nonblock(stream->real_stream->fd, !blocking); |
196 | 0 | prev_fd = stream->real_stream->fd; |
197 | 0 | } |
198 | 0 | stream = stream->real_stream->parent; |
199 | 0 | } while (stream != NULL); |
200 | 0 | } |
201 | | |
202 | | static void i_stream_update(struct istream_private *stream) |
203 | 29.7k | { |
204 | 29.7k | if (stream->parent == NULL) |
205 | 29.7k | stream->access_counter++; |
206 | 0 | else { |
207 | 0 | stream->access_counter = |
208 | 0 | stream->parent->real_stream->access_counter; |
209 | 0 | stream->parent_expected_offset = stream->parent->v_offset; |
210 | 0 | } |
211 | 29.7k | } |
212 | | |
213 | | static bool snapshot_has_memarea(struct istream_snapshot *snapshot, |
214 | | struct memarea *memarea) |
215 | 0 | { |
216 | 0 | if (snapshot->old_memarea == memarea) |
217 | 0 | return TRUE; |
218 | 0 | if (snapshot->prev_snapshot != NULL) |
219 | 0 | return snapshot_has_memarea(snapshot->prev_snapshot, memarea); |
220 | 0 | return FALSE; |
221 | 0 | } |
222 | | |
223 | | struct istream_snapshot * |
224 | | i_stream_default_snapshot(struct istream_private *stream, |
225 | | struct istream_snapshot *prev_snapshot) |
226 | 0 | { |
227 | 0 | struct istream_snapshot *snapshot; |
228 | |
|
229 | 0 | if (stream->memarea != NULL) { |
230 | 0 | if (prev_snapshot != NULL) { |
231 | 0 | if (snapshot_has_memarea(prev_snapshot, stream->memarea)) |
232 | 0 | return prev_snapshot; |
233 | 0 | } |
234 | | /* This stream has a memarea. Reference it, so we can later on |
235 | | rollback if needed. */ |
236 | 0 | snapshot = i_new(struct istream_snapshot, 1); |
237 | 0 | snapshot->old_memarea = stream->memarea; |
238 | 0 | snapshot->prev_snapshot = prev_snapshot; |
239 | 0 | memarea_ref(snapshot->old_memarea); |
240 | 0 | return snapshot; |
241 | 0 | } |
242 | 0 | if (stream->parent == NULL) { |
243 | 0 | if (stream->nonpersistent_buffers) { |
244 | | /* Assume that memarea would be used normally, but |
245 | | now it's NULL because the buffer is empty and |
246 | | empty buffers are freed. */ |
247 | 0 | i_assert(stream->skip == stream->pos); |
248 | 0 | return prev_snapshot; |
249 | 0 | } |
250 | 0 | i_panic("%s is missing istream.snapshot() implementation", |
251 | 0 | i_stream_get_name(&stream->istream)); |
252 | 0 | } |
253 | 0 | struct istream_private *_parent_stream = |
254 | 0 | stream->parent->real_stream; |
255 | 0 | return _parent_stream->snapshot(_parent_stream, prev_snapshot); |
256 | 0 | } |
257 | | |
258 | | void i_stream_snapshot_free(struct istream_snapshot **_snapshot) |
259 | 14.8k | { |
260 | 14.8k | struct istream_snapshot *snapshot = *_snapshot; |
261 | | |
262 | 14.8k | if (*_snapshot == NULL) |
263 | 14.8k | return; |
264 | 0 | *_snapshot = NULL; |
265 | |
|
266 | 0 | i_stream_snapshot_free(&snapshot->prev_snapshot); |
267 | 0 | if (snapshot->free != NULL) |
268 | 0 | snapshot->free(snapshot); |
269 | 0 | else { |
270 | 0 | if (snapshot->old_memarea != NULL) |
271 | 0 | memarea_unref(&snapshot->old_memarea); |
272 | 0 | i_stream_unref(&snapshot->istream); |
273 | 0 | i_free(snapshot); |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | | static struct istream_snapshot * |
278 | | i_stream_noop_snapshot(struct istream_private *stream ATTR_UNUSED, |
279 | | struct istream_snapshot *prev_snapshot) |
280 | 75 | { |
281 | 75 | return prev_snapshot; |
282 | 75 | } |
283 | | |
284 | | static struct istream_private * |
285 | | i_stream_get_io_parent(struct istream_private *_stream) |
286 | 23.4k | { |
287 | 23.4k | if (_stream->parent != NULL) |
288 | 0 | return _stream->parent->real_stream; |
289 | 23.4k | if (_stream->io_parent != NULL) |
290 | 11.7k | return _stream->io_parent->real_stream; |
291 | 11.7k | return NULL; |
292 | 23.4k | } |
293 | | |
294 | | static bool i_stream_is_io_pending_until_read(struct istream_private *_stream) |
295 | 11.7k | { |
296 | 11.7k | struct istream_private *parent; |
297 | | |
298 | 23.4k | while (!_stream->io_pending_until_read && |
299 | 23.4k | (parent = i_stream_get_io_parent(_stream)) != NULL) |
300 | 11.7k | _stream = parent; |
301 | 11.7k | return _stream->io_pending_until_read; |
302 | 11.7k | } |
303 | | |
304 | | ssize_t i_stream_read(struct istream *stream) |
305 | 14.8k | { |
306 | 14.8k | struct istream_private *_stream = stream->real_stream; |
307 | 14.8k | ssize_t ret; |
308 | | #ifdef DEBUG |
309 | | unsigned char prev_buf[4]; |
310 | | const unsigned char *prev_data = _stream->buffer; |
311 | | size_t prev_skip = _stream->skip, prev_pos = _stream->pos; |
312 | | bool invalid = i_stream_is_buffer_invalid(_stream); |
313 | | |
314 | | i_assert(prev_skip <= prev_pos); |
315 | | size_t prev_size = prev_pos - prev_skip; |
316 | | if (invalid) |
317 | | ; |
318 | | else if (prev_size > 4) { |
319 | | memcpy(prev_buf, prev_data + prev_skip, 2); |
320 | | memcpy(prev_buf+2, prev_data + prev_pos - 2, 2); |
321 | | } else if (prev_size > 0) { |
322 | | memcpy(prev_buf, prev_data + prev_skip, prev_size); |
323 | | } |
324 | | #endif |
325 | | |
326 | 14.8k | if (_stream->skip != _stream->pos || _stream->prev_snapshot != NULL) { |
327 | 75 | _stream->prev_snapshot = |
328 | 75 | _stream->snapshot(_stream, _stream->prev_snapshot); |
329 | 75 | } |
330 | 14.8k | ret = i_stream_read_memarea(stream); |
331 | 14.8k | if (ret > 0) |
332 | 11.9k | i_stream_snapshot_free(&_stream->prev_snapshot); |
333 | | #ifdef DEBUG |
334 | | else if (!invalid) { |
335 | | i_assert((_stream->pos - _stream->skip) == (prev_pos - prev_skip) || |
336 | | prev_pos == prev_skip); |
337 | | if (prev_data == NULL) |
338 | | i_assert(prev_pos == prev_skip); |
339 | | else if (prev_pos - prev_skip <= 4) |
340 | | i_assert(memcmp(prev_buf, prev_data + prev_skip, prev_pos - prev_skip) == 0); |
341 | | else { |
342 | | i_assert(memcmp(prev_buf, prev_data + prev_skip, 2) == 0); |
343 | | i_assert(memcmp(prev_buf+2, prev_data + prev_pos - 2, 2) == 0); |
344 | | } |
345 | | } |
346 | | #endif |
347 | 14.8k | if (!_stream->istream.eof && |
348 | 11.7k | i_stream_is_io_pending_until_read(_stream)) { |
349 | | /* One of the parent istreams still has IO pending, because its |
350 | | read() wasn't called. Set IO back to pending to prevent |
351 | | hangs. */ |
352 | 0 | i_stream_set_input_pending(stream, TRUE); |
353 | 0 | } |
354 | 14.8k | return ret; |
355 | 14.8k | } |
356 | | |
357 | | /* The istreams whose read() is currently running, innermost first. Used for |
358 | | verifying that istreams declare the istreams they read. */ |
359 | | struct istream_reader { |
360 | | const struct istream_reader *prev; |
361 | | struct istream *stream; |
362 | | /* The ioloop that was running when read() was called. A nested |
363 | | io_loop_run() (e.g. dict_wait()) runs unrelated istreams, which |
364 | | this istream isn't reading. */ |
365 | | struct ioloop *ioloop; |
366 | | }; |
367 | | static const struct istream_reader *istream_cur_reader = NULL; |
368 | | |
369 | | static void i_stream_verify_reader(struct istream *stream) |
370 | 27.9k | { |
371 | 27.9k | struct istream_private *reader; |
372 | | |
373 | 27.9k | if (istream_cur_reader == NULL || istream_cur_reader->stream == stream) |
374 | 13.3k | return; |
375 | 14.5k | if (istream_cur_reader->ioloop != current_ioloop) { |
376 | | /* Running in a nested ioloop, so this istream is unrelated to |
377 | | the istream whose read() is running. */ |
378 | 0 | return; |
379 | 0 | } |
380 | 14.5k | if (stream->blocking) { |
381 | | /* Blocking istreams are read until they're finished, so their |
382 | | ioloop IO doesn't matter. read() implementations may create |
383 | | and drain such istreams internally (e.g. a temp file). */ |
384 | 14.5k | return; |
385 | 14.5k | } |
386 | 0 | if (istream_cur_reader->stream->blocking) { |
387 | | /* A blocking istream is also read until it's finished, so it |
388 | | never depends on an ioloop IO to wake it up, and it doesn't |
389 | | matter which istreams it reads. */ |
390 | 0 | return; |
391 | 0 | } |
392 | | |
393 | 0 | reader = istream_cur_reader->stream->real_stream; |
394 | 0 | if (stream == reader->parent) |
395 | 0 | return; |
396 | 0 | if (reader->io_parent != NULL && |
397 | 0 | i_stream_get_root_io(stream) == |
398 | 0 | i_stream_get_root_io(reader->io_parent)) { |
399 | | /* The declared istream, or another istream reading from the |
400 | | same one (e.g. istream-decompress reads both its input and |
401 | | the decompressing istream created on top of it). */ |
402 | 0 | return; |
403 | 0 | } |
404 | 0 | if (reader->hidden_inputs == ISTREAM_HIDDEN_INPUTS_UNCHECKED || |
405 | 0 | reader->hidden_inputs == ISTREAM_HIDDEN_INPUTS_PANIC) { |
406 | | /* Reads istreams it doesn't declare, so there's nothing to |
407 | | compare against. */ |
408 | 0 | return; |
409 | 0 | } |
410 | | |
411 | 0 | i_panic("istream %s reads undeclared istream %s " |
412 | 0 | "(missing istream_private.io_parent?)", |
413 | 0 | i_stream_get_name(&reader->istream), |
414 | 0 | i_stream_get_name(stream)); |
415 | 0 | } |
416 | | |
417 | | ssize_t i_stream_read_memarea(struct istream *stream) |
418 | 28.0k | { |
419 | 28.0k | struct istream_private *_stream = stream->real_stream; |
420 | 28.0k | size_t old_size; |
421 | 28.0k | ssize_t ret; |
422 | | |
423 | 28.0k | if (unlikely(stream->closed || stream->stream_errno != 0)) { |
424 | 160 | stream->eof = TRUE; |
425 | 160 | errno = stream->stream_errno; |
426 | 160 | return -1; |
427 | 160 | } |
428 | | |
429 | 27.9k | i_stream_verify_reader(stream); |
430 | 27.9k | stream->eof = FALSE; |
431 | | |
432 | 27.9k | if (_stream->parent != NULL) |
433 | 0 | i_stream_seek(_stream->parent, _stream->parent_expected_offset); |
434 | | |
435 | 27.9k | old_size = _stream->pos - _stream->skip; |
436 | 27.9k | if (_stream->pos < _stream->high_pos) { |
437 | | /* we're here because we seeked back within the read buffer. */ |
438 | 0 | ret = _stream->high_pos - _stream->pos; |
439 | 0 | _stream->pos = _stream->high_pos; |
440 | 0 | _stream->high_pos = 0; |
441 | 27.9k | } else { |
442 | 27.9k | struct istream_reader reader = { |
443 | 27.9k | .prev = istream_cur_reader, |
444 | 27.9k | .stream = stream, |
445 | 27.9k | .ioloop = current_ioloop, |
446 | 27.9k | }; |
447 | | |
448 | 27.9k | _stream->high_pos = 0; |
449 | 27.9k | _stream->io_pending_until_read = FALSE; |
450 | 27.9k | istream_cur_reader = &reader; |
451 | 27.9k | ret = _stream->read(_stream); |
452 | 27.9k | istream_cur_reader = reader.prev; |
453 | 27.9k | } |
454 | 27.9k | i_assert(_stream->skip <= _stream->pos); |
455 | 27.9k | i_assert(old_size <= _stream->pos - _stream->skip); |
456 | 27.9k | switch (ret) { |
457 | 0 | case -2: |
458 | 0 | i_assert(_stream->skip != _stream->pos); |
459 | 0 | break; |
460 | 4.28k | case -1: |
461 | 4.28k | if (stream->stream_errno != 0) { |
462 | | /* error handling should be easier if we now just |
463 | | assume the stream is now at EOF */ |
464 | 602 | stream->eof = TRUE; |
465 | 602 | errno = stream->stream_errno; |
466 | 3.67k | } else { |
467 | 3.67k | i_assert(stream->eof); |
468 | 3.67k | i_assert(old_size == _stream->pos - _stream->skip); |
469 | 3.67k | } |
470 | 4.28k | break; |
471 | 4.28k | case 0: |
472 | 0 | i_assert(!stream->blocking); |
473 | 0 | break; |
474 | 23.6k | default: |
475 | 23.6k | i_assert(ret > 0); |
476 | 23.6k | i_assert(_stream->skip < _stream->pos); |
477 | 23.6k | i_assert((size_t)ret+old_size == _stream->pos - _stream->skip); |
478 | 23.6k | _stream->last_read_timeval = ioloop_timeval; |
479 | 23.6k | break; |
480 | 27.9k | } |
481 | | |
482 | 27.9k | if (stream->stream_errno != 0) { |
483 | | /* error handling should be easier if we now just |
484 | | assume the stream is now at EOF. Note that we could get here |
485 | | even if read() didn't return -1, although that's a little |
486 | | bit sloppy istream implementation. */ |
487 | 762 | stream->eof = TRUE; |
488 | 762 | } |
489 | | |
490 | 27.9k | i_stream_update(_stream); |
491 | | /* verify that parents' access_counters are valid. the parent's |
492 | | i_stream_read() should guarantee this. */ |
493 | 27.9k | i_assert(!i_stream_is_buffer_invalid(_stream)); |
494 | 27.9k | return ret; |
495 | 27.9k | } |
496 | | |
497 | | int i_stream_read_more_memarea(struct istream *stream, |
498 | | const unsigned char **data_r, size_t *size_r) |
499 | 0 | { |
500 | 0 | *data_r = i_stream_get_data(stream, size_r); |
501 | 0 | if (*size_r > 0) |
502 | 0 | return 1; |
503 | | |
504 | 0 | int ret = i_stream_read_memarea(stream); |
505 | 0 | *data_r = i_stream_get_data(stream, size_r); |
506 | 0 | return ret; |
507 | 0 | } |
508 | | |
509 | | void i_stream_get_last_read_time(struct istream *stream, struct timeval *tv_r) |
510 | 0 | { |
511 | 0 | *tv_r = stream->real_stream->last_read_timeval; |
512 | 0 | } |
513 | | |
514 | | ssize_t i_stream_read_copy_from_parent(struct istream *istream) |
515 | 0 | { |
516 | 0 | struct istream_private *stream = istream->real_stream; |
517 | 0 | size_t pos; |
518 | 0 | ssize_t ret; |
519 | |
|
520 | 0 | stream->pos -= stream->skip; |
521 | 0 | stream->skip = 0; |
522 | |
|
523 | 0 | stream->buffer = i_stream_get_data(stream->parent, &pos); |
524 | 0 | if (pos > stream->pos) |
525 | 0 | ret = 0; |
526 | 0 | else do { |
527 | 0 | ret = i_stream_read_memarea(stream->parent); |
528 | 0 | stream->istream.stream_errno = stream->parent->stream_errno; |
529 | 0 | stream->istream.eof = stream->parent->eof; |
530 | 0 | stream->buffer = i_stream_get_data(stream->parent, &pos); |
531 | | /* check again, in case the parent stream had been seeked |
532 | | backwards and the previous read() didn't get us far |
533 | | enough. */ |
534 | 0 | } while (pos <= stream->pos && ret > 0); |
535 | 0 | if (ret == -2) { |
536 | 0 | i_stream_update(stream); |
537 | 0 | return -2; |
538 | 0 | } |
539 | | |
540 | 0 | ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : |
541 | 0 | (ret == 0 ? 0 : -1); |
542 | 0 | stream->pos = pos; |
543 | 0 | i_assert(ret != -1 || stream->istream.eof || |
544 | 0 | stream->istream.stream_errno != 0); |
545 | 0 | i_stream_update(stream); |
546 | 0 | return ret; |
547 | 0 | } |
548 | | |
549 | | void i_stream_free_buffer(struct istream_private *stream) |
550 | 2.95k | { |
551 | 2.95k | if (stream->memarea != NULL) { |
552 | 1.94k | memarea_unref(&stream->memarea); |
553 | 1.94k | stream->w_buffer = NULL; |
554 | 1.94k | } else if (stream->w_buffer != NULL) { |
555 | 0 | i_free_and_null(stream->w_buffer); |
556 | 1.01k | } else { |
557 | | /* don't know how to free it */ |
558 | 1.01k | return; |
559 | 1.01k | } |
560 | 1.94k | stream->buffer_size = 0; |
561 | 1.94k | } |
562 | | |
563 | | void i_stream_skip(struct istream *stream, uoff_t count) |
564 | 27.4k | { |
565 | 27.4k | struct istream_private *_stream = stream->real_stream; |
566 | 27.4k | size_t data_size; |
567 | | |
568 | 27.4k | data_size = _stream->pos - _stream->skip; |
569 | 27.4k | if (count <= data_size) { |
570 | | /* within buffer */ |
571 | 27.4k | stream->v_offset += count; |
572 | 27.4k | _stream->skip += count; |
573 | 27.4k | if (_stream->nonpersistent_buffers && |
574 | 0 | _stream->skip == _stream->pos) { |
575 | 0 | _stream->skip = _stream->pos = 0; |
576 | 0 | i_stream_free_buffer(_stream); |
577 | 0 | } |
578 | 27.4k | return; |
579 | 27.4k | } |
580 | | |
581 | | /* have to seek forward */ |
582 | 0 | count -= data_size; |
583 | 0 | _stream->skip = _stream->pos; |
584 | 0 | stream->v_offset += data_size; |
585 | |
|
586 | 0 | if (unlikely(stream->closed || stream->stream_errno != 0)) |
587 | 0 | return; |
588 | | |
589 | 0 | _stream->seek(_stream, stream->v_offset + count, FALSE); |
590 | 0 | } |
591 | | |
592 | | static bool i_stream_can_optimize_seek(struct istream_private *stream) |
593 | 0 | { |
594 | 0 | if (stream->parent == NULL) |
595 | 0 | return TRUE; |
596 | | |
597 | | /* use the fast route only if the parent stream hasn't been changed */ |
598 | 0 | if (stream->access_counter != |
599 | 0 | stream->parent->real_stream->access_counter) |
600 | 0 | return FALSE; |
601 | | |
602 | 0 | return i_stream_can_optimize_seek(stream->parent->real_stream); |
603 | 0 | } |
604 | | |
605 | | void i_stream_seek(struct istream *stream, uoff_t v_offset) |
606 | 1.77k | { |
607 | 1.77k | struct istream_private *_stream = stream->real_stream; |
608 | | |
609 | 1.77k | if (v_offset >= stream->v_offset && |
610 | 0 | i_stream_can_optimize_seek(_stream)) |
611 | 0 | i_stream_skip(stream, v_offset - stream->v_offset); |
612 | 1.77k | else { |
613 | 1.77k | if (unlikely(stream->closed || stream->stream_errno != 0)) { |
614 | 0 | stream->eof = TRUE; |
615 | 0 | return; |
616 | 0 | } |
617 | 1.77k | stream->eof = FALSE; |
618 | 1.77k | _stream->seek(_stream, v_offset, FALSE); |
619 | 1.77k | } |
620 | 1.77k | i_stream_update(_stream); |
621 | 1.77k | } |
622 | | |
623 | | void i_stream_seek_mark(struct istream *stream, uoff_t v_offset) |
624 | 0 | { |
625 | 0 | struct istream_private *_stream = stream->real_stream; |
626 | |
|
627 | 0 | if (unlikely(stream->closed || stream->stream_errno != 0)) |
628 | 0 | return; |
629 | | |
630 | 0 | stream->eof = FALSE; |
631 | 0 | _stream->seek(_stream, v_offset, TRUE); |
632 | 0 | i_stream_update(_stream); |
633 | 0 | } |
634 | | |
635 | | void i_stream_sync(struct istream *stream) |
636 | 0 | { |
637 | 0 | struct istream_private *_stream = stream->real_stream; |
638 | |
|
639 | 0 | if (unlikely(stream->closed || stream->stream_errno != 0)) |
640 | 0 | return; |
641 | | |
642 | 0 | if (_stream->sync != NULL) { |
643 | 0 | _stream->sync(_stream); |
644 | 0 | i_stream_update(_stream); |
645 | 0 | } |
646 | 0 | } |
647 | | |
648 | | int i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r) |
649 | 0 | { |
650 | 0 | struct istream_private *_stream = stream->real_stream; |
651 | |
|
652 | 0 | if (unlikely(stream->closed || stream->stream_errno != 0)) |
653 | 0 | return -1; |
654 | | |
655 | 0 | if (_stream->stat(_stream, exact) < 0) { |
656 | 0 | stream->eof = TRUE; |
657 | 0 | return -1; |
658 | 0 | } |
659 | 0 | *st_r = &_stream->statbuf; |
660 | 0 | return 0; |
661 | 0 | } |
662 | | |
663 | | int i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r) |
664 | 0 | { |
665 | 0 | struct istream_private *_stream = stream->real_stream; |
666 | |
|
667 | 0 | if (unlikely(stream->closed || stream->stream_errno != 0)) |
668 | 0 | return -1; |
669 | | |
670 | 0 | int ret; |
671 | 0 | if ((ret = _stream->get_size(_stream, exact, size_r)) < 0) |
672 | 0 | stream->eof = TRUE; |
673 | 0 | return ret; |
674 | 0 | } |
675 | | |
676 | | bool i_stream_have_bytes_left(struct istream *stream) |
677 | 0 | { |
678 | 0 | return i_stream_get_data_size(stream) > 0 || !stream->eof; |
679 | 0 | } |
680 | | |
681 | | bool i_stream_read_eof(struct istream *stream) |
682 | 0 | { |
683 | 0 | if (i_stream_get_data_size(stream) == 0) |
684 | 0 | (void)i_stream_read(stream); |
685 | 0 | return !i_stream_have_bytes_left(stream); |
686 | 0 | } |
687 | | |
688 | | uoff_t i_stream_get_absolute_offset(struct istream *stream) |
689 | 0 | { |
690 | 0 | uoff_t abs_offset = stream->v_offset; |
691 | 0 | while (stream != NULL) { |
692 | 0 | abs_offset += stream->real_stream->start_offset; |
693 | 0 | stream = stream->real_stream->parent; |
694 | 0 | } |
695 | 0 | return abs_offset; |
696 | 0 | } |
697 | | |
698 | | static char *i_stream_next_line_finish(struct istream_private *stream, size_t i) |
699 | 0 | { |
700 | 0 | char *ret; |
701 | 0 | size_t end; |
702 | |
|
703 | 0 | if (i > stream->skip && stream->buffer[i-1] == '\r') { |
704 | 0 | end = i - 1; |
705 | 0 | stream->line_crlf = TRUE; |
706 | 0 | } else { |
707 | 0 | end = i; |
708 | 0 | stream->line_crlf = FALSE; |
709 | 0 | } |
710 | |
|
711 | 0 | if (stream->buffer == stream->w_buffer && |
712 | 0 | end < stream->buffer_size) { |
713 | | /* modify the buffer directly */ |
714 | 0 | stream->w_buffer[end] = '\0'; |
715 | 0 | ret = (char *)stream->w_buffer + stream->skip; |
716 | 0 | } else { |
717 | | /* use a temporary string to return it */ |
718 | 0 | if (stream->line_str == NULL) |
719 | 0 | stream->line_str = str_new(default_pool, 256); |
720 | 0 | str_truncate(stream->line_str, 0); |
721 | 0 | if (stream->skip < end) |
722 | 0 | str_append_data(stream->line_str, stream->buffer + stream->skip, |
723 | 0 | end - stream->skip); |
724 | 0 | ret = str_c_modifiable(stream->line_str); |
725 | 0 | } |
726 | |
|
727 | 0 | if (i < stream->pos) |
728 | 0 | i++; |
729 | 0 | stream->istream.v_offset += i - stream->skip; |
730 | 0 | stream->skip = i; |
731 | 0 | return ret; |
732 | 0 | } |
733 | | |
734 | | static char *i_stream_last_line(struct istream_private *_stream) |
735 | 0 | { |
736 | 0 | if (_stream->istream.eof && _stream->skip != _stream->pos && |
737 | 0 | _stream->return_nolf_line) { |
738 | | /* the last line is missing LF and we want to return it. */ |
739 | 0 | return i_stream_next_line_finish(_stream, _stream->pos); |
740 | 0 | } |
741 | 0 | return NULL; |
742 | 0 | } |
743 | | |
744 | | char *i_stream_next_line(struct istream *stream) |
745 | 0 | { |
746 | 0 | struct istream_private *_stream = stream->real_stream; |
747 | 0 | const unsigned char *pos; |
748 | |
|
749 | 0 | if (_stream->skip >= _stream->pos) |
750 | 0 | return NULL; |
751 | | |
752 | 0 | pos = memchr(_stream->buffer + _stream->skip, '\n', |
753 | 0 | _stream->pos - _stream->skip); |
754 | 0 | if (pos != NULL) { |
755 | 0 | return i_stream_next_line_finish(_stream, |
756 | 0 | pos - _stream->buffer); |
757 | 0 | } else { |
758 | 0 | return i_stream_last_line(_stream); |
759 | 0 | } |
760 | 0 | } |
761 | | |
762 | | char *i_stream_read_next_line(struct istream *stream) |
763 | 0 | { |
764 | 0 | char *line; |
765 | |
|
766 | 0 | for (;;) { |
767 | 0 | line = i_stream_next_line(stream); |
768 | 0 | if (line != NULL) |
769 | 0 | break; |
770 | | |
771 | 0 | switch (i_stream_read(stream)) { |
772 | 0 | case -2: |
773 | 0 | io_stream_set_error(&stream->real_stream->iostream, |
774 | 0 | "Line is too long (over %zu" |
775 | 0 | " bytes at offset %"PRIuUOFF_T")", |
776 | 0 | i_stream_get_data_size(stream), stream->v_offset); |
777 | 0 | stream->stream_errno = errno = ENOBUFS; |
778 | 0 | stream->eof = TRUE; |
779 | 0 | return NULL; |
780 | 0 | case -1: |
781 | 0 | return i_stream_last_line(stream->real_stream); |
782 | 0 | case 0: |
783 | 0 | return NULL; |
784 | 0 | } |
785 | 0 | } |
786 | 0 | return line; |
787 | 0 | } |
788 | | |
789 | | bool i_stream_last_line_crlf(struct istream *stream) |
790 | 0 | { |
791 | 0 | return stream->real_stream->line_crlf; |
792 | 0 | } |
793 | | |
794 | | static bool i_stream_is_buffer_invalid(const struct istream_private *stream) |
795 | 53.5k | { |
796 | 53.5k | if (stream->parent == NULL) { |
797 | | /* the buffer can't point to parent, because it doesn't exist */ |
798 | 53.5k | return FALSE; |
799 | 53.5k | } |
800 | 0 | if (stream->w_buffer != NULL) { |
801 | | /* we can pretty safely assume that the stream is using its |
802 | | own private buffer, so it can never become invalid. */ |
803 | 0 | return FALSE; |
804 | 0 | } |
805 | 0 | if (stream->access_counter != |
806 | 0 | stream->parent->real_stream->access_counter) { |
807 | | /* parent has been modified behind this stream, we can't trust |
808 | | that our buffer is valid */ |
809 | 0 | return TRUE; |
810 | 0 | } |
811 | 0 | return i_stream_is_buffer_invalid(stream->parent->real_stream); |
812 | 0 | } |
813 | | |
814 | | const unsigned char * |
815 | | i_stream_get_data(struct istream *stream, size_t *size_r) |
816 | 59.0k | { |
817 | 59.0k | struct istream_private *_stream = stream->real_stream; |
818 | | |
819 | 59.0k | if (_stream->skip >= _stream->pos) { |
820 | 33.4k | *size_r = 0; |
821 | 33.4k | return uchar_empty_ptr; |
822 | 33.4k | } |
823 | | |
824 | 25.6k | if (unlikely(i_stream_is_buffer_invalid(_stream))) { |
825 | | /* This stream may be using parent's buffer directly as |
826 | | _stream->buffer, but the parent stream has already been |
827 | | modified indirectly. This means that the buffer might no |
828 | | longer point to where we assume it points to. So we'll |
829 | | just return the stream as empty until it's read again. |
830 | | |
831 | | It's a bit ugly to suddenly drop data from the stream that |
832 | | was already read, but since this happens only with shared |
833 | | parent istreams the caller is hopefully aware enough that |
834 | | something like this might happen. The other solutions would |
835 | | be to a) try to automatically read the data back (but we |
836 | | can't handle errors..) or b) always copy data to stream's |
837 | | own buffer instead of pointing to parent's buffer (but this |
838 | | causes data copying that is nearly always unnecessary). */ |
839 | 0 | *size_r = 0; |
840 | | /* if we had already read until EOF, mark the stream again as |
841 | | not being at the end of file. */ |
842 | 0 | if (stream->stream_errno == 0) { |
843 | 0 | _stream->skip = _stream->pos = 0; |
844 | 0 | stream->eof = FALSE; |
845 | 0 | } |
846 | 0 | return uchar_empty_ptr; |
847 | 0 | } |
848 | | |
849 | 25.6k | *size_r = _stream->pos - _stream->skip; |
850 | 25.6k | return _stream->buffer + _stream->skip; |
851 | 25.6k | } |
852 | | |
853 | | size_t i_stream_get_data_size(struct istream *stream) |
854 | 0 | { |
855 | 0 | size_t size; |
856 | |
|
857 | 0 | (void)i_stream_get_data(stream, &size); |
858 | 0 | return size; |
859 | 0 | } |
860 | | |
861 | | unsigned char *i_stream_get_modifiable_data(struct istream *stream, |
862 | | size_t *size_r) |
863 | 0 | { |
864 | 0 | struct istream_private *_stream = stream->real_stream; |
865 | |
|
866 | 0 | if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) { |
867 | 0 | *size_r = 0; |
868 | 0 | return NULL; |
869 | 0 | } |
870 | | |
871 | 0 | *size_r = _stream->pos - _stream->skip; |
872 | 0 | return _stream->w_buffer + _stream->skip; |
873 | 0 | } |
874 | | |
875 | | int i_stream_read_data(struct istream *stream, const unsigned char **data_r, |
876 | | size_t *size_r, size_t threshold) |
877 | 16.4k | { |
878 | 16.4k | ssize_t ret = 0; |
879 | 16.4k | bool read_more = FALSE; |
880 | | |
881 | 28.3k | do { |
882 | 28.3k | *data_r = i_stream_get_data(stream, size_r); |
883 | 28.3k | if (*size_r > threshold) |
884 | 13.5k | return 1; |
885 | | |
886 | | /* we need more data */ |
887 | 14.8k | ret = i_stream_read(stream); |
888 | 14.8k | if (ret > 0) |
889 | 11.9k | read_more = TRUE; |
890 | 14.8k | } while (ret > 0); |
891 | | |
892 | 2.91k | *data_r = i_stream_get_data(stream, size_r); |
893 | 2.91k | if (ret == -2) |
894 | 0 | return -2; |
895 | | |
896 | 2.91k | if (ret == 0) { |
897 | | /* need to read more */ |
898 | 0 | i_assert(!stream->blocking); |
899 | 0 | return 0; |
900 | 0 | } |
901 | 2.91k | if (stream->stream_errno == 0 && read_more) { |
902 | | /* we read at least some new data */ |
903 | 0 | return 0; |
904 | 0 | } |
905 | 2.91k | return -1; |
906 | 2.91k | } |
907 | | |
908 | | int i_stream_read_limited(struct istream *stream, const unsigned char **data_r, |
909 | | size_t *size_r, size_t limit) |
910 | 0 | { |
911 | 0 | struct istream_private *_stream = stream->real_stream; |
912 | 0 | int ret; |
913 | |
|
914 | 0 | *data_r = i_stream_get_data(stream, size_r); |
915 | 0 | if (*size_r >= limit) { |
916 | 0 | *size_r = limit; |
917 | 0 | return 1; |
918 | 0 | } |
919 | | |
920 | 0 | _stream->data_limit = limit; |
921 | 0 | ret = i_stream_read_more(stream, data_r, size_r); |
922 | 0 | _stream->data_limit = 0; |
923 | |
|
924 | 0 | if (*size_r >= limit) |
925 | 0 | *size_r = limit; |
926 | 0 | return ret; |
927 | 0 | } |
928 | | |
929 | | void i_stream_compress(struct istream_private *stream) |
930 | 10.5k | { |
931 | 10.5k | i_assert(stream->memarea == NULL || |
932 | 10.5k | memarea_get_refcount(stream->memarea) == 1); |
933 | | |
934 | 10.5k | if (stream->skip != stream->pos) { |
935 | 0 | memmove(stream->w_buffer, stream->w_buffer + stream->skip, |
936 | 0 | stream->pos - stream->skip); |
937 | 0 | } |
938 | 10.5k | stream->pos -= stream->skip; |
939 | | |
940 | 10.5k | stream->skip = 0; |
941 | 10.5k | } |
942 | | |
943 | | static void i_stream_w_buffer_free(void *buf) |
944 | 752 | { |
945 | 752 | i_free(buf); |
946 | 752 | } |
947 | | |
948 | | static void |
949 | | i_stream_w_buffer_realloc(struct istream_private *stream, size_t old_size) |
950 | 752 | { |
951 | 752 | void *new_buffer; |
952 | | |
953 | 752 | if (stream->memarea != NULL && |
954 | 752 | memarea_get_refcount(stream->memarea) == 1) { |
955 | | /* Nobody else is referencing the memarea. |
956 | | We can just reallocate it. */ |
957 | 0 | memarea_free_without_callback(&stream->memarea); |
958 | 0 | new_buffer = i_realloc(stream->w_buffer, old_size, |
959 | 0 | stream->buffer_size); |
960 | 752 | } else { |
961 | 752 | new_buffer = i_malloc(stream->buffer_size); |
962 | 752 | if (old_size > 0) { |
963 | 0 | i_assert(stream->w_buffer != NULL); |
964 | 0 | memcpy(new_buffer, stream->w_buffer, old_size); |
965 | 0 | } |
966 | 752 | if (stream->memarea != NULL) |
967 | 752 | memarea_unref(&stream->memarea); |
968 | 752 | } |
969 | | |
970 | 752 | stream->w_buffer = new_buffer; |
971 | 752 | stream->buffer = new_buffer; |
972 | | |
973 | 752 | stream->memarea = memarea_init(stream->w_buffer, stream->buffer_size, |
974 | 752 | i_stream_w_buffer_free, new_buffer); |
975 | 752 | } |
976 | | |
977 | | void i_stream_grow_buffer(struct istream_private *stream, size_t bytes) |
978 | 891 | { |
979 | 891 | size_t old_size, max_size; |
980 | | |
981 | 891 | old_size = stream->buffer_size; |
982 | | |
983 | 891 | stream->buffer_size = stream->pos + bytes; |
984 | 891 | if (stream->buffer_size <= stream->init_buffer_size) |
985 | 891 | stream->buffer_size = stream->init_buffer_size; |
986 | 0 | else |
987 | 0 | stream->buffer_size = nearest_power(stream->buffer_size); |
988 | | |
989 | 891 | max_size = i_stream_get_max_buffer_size(&stream->istream); |
990 | 891 | i_assert(max_size > 0); |
991 | 891 | if (stream->buffer_size > max_size) |
992 | 0 | stream->buffer_size = max_size; |
993 | | |
994 | 891 | if (stream->buffer_size <= old_size) |
995 | 139 | stream->buffer_size = old_size; |
996 | 752 | else |
997 | 752 | i_stream_w_buffer_realloc(stream, old_size); |
998 | 891 | } |
999 | | |
1000 | | bool i_stream_try_alloc(struct istream_private *stream, |
1001 | | size_t wanted_size, size_t *size_r) |
1002 | 11.9k | { |
1003 | 11.9k | i_assert(wanted_size > 0); |
1004 | 11.9k | i_assert(stream->buffer_size >= stream->pos); |
1005 | | |
1006 | 11.9k | if (wanted_size > stream->buffer_size - stream->pos) { |
1007 | 11.4k | if (stream->skip > 0) { |
1008 | | /* remove the unused bytes from beginning of buffer */ |
1009 | 10.5k | if (stream->memarea != NULL && |
1010 | 10.5k | memarea_get_refcount(stream->memarea) > 1) { |
1011 | | /* The memarea is still referenced. We can't |
1012 | | overwrite data until extra references are |
1013 | | gone. */ |
1014 | 0 | i_stream_w_buffer_realloc(stream, stream->buffer_size); |
1015 | 0 | } |
1016 | 10.5k | i_stream_compress(stream); |
1017 | 10.5k | } else if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream)) { |
1018 | | /* buffer is full - grow it */ |
1019 | 891 | i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE); |
1020 | 891 | } |
1021 | 11.4k | } |
1022 | | |
1023 | 11.9k | if (stream->data_limit == 0 || |
1024 | 0 | (stream->buffer_size - stream->skip) < stream->data_limit) |
1025 | 11.9k | *size_r = stream->buffer_size - stream->pos; |
1026 | 0 | else { |
1027 | 0 | size_t buffered = (stream->pos - stream->skip); |
1028 | |
|
1029 | 0 | if (buffered >= stream->data_limit) |
1030 | 0 | *size_r = 0; |
1031 | 0 | else |
1032 | 0 | *size_r = stream->data_limit - buffered; |
1033 | 0 | } |
1034 | 11.9k | i_assert(stream->w_buffer != NULL || *size_r == 0); |
1035 | 11.9k | return *size_r > 0; |
1036 | 11.9k | } |
1037 | | |
1038 | | bool ATTR_NOWARN_UNUSED_RESULT |
1039 | | i_stream_try_alloc_avoid_compress(struct istream_private *stream, |
1040 | | size_t wanted_size, size_t *size_r) |
1041 | 0 | { |
1042 | 0 | size_t old_skip = stream->skip; |
1043 | | |
1044 | | /* try first with skip=0, so no compression is done */ |
1045 | 0 | stream->skip = 0; |
1046 | 0 | bool ret = i_stream_try_alloc(stream, wanted_size, size_r); |
1047 | 0 | stream->skip = old_skip; |
1048 | 0 | if (ret || old_skip == 0) |
1049 | 0 | return ret; |
1050 | | /* it's full. try with compression. */ |
1051 | 0 | return i_stream_try_alloc(stream, wanted_size, size_r); |
1052 | 0 | } |
1053 | | |
1054 | | void *i_stream_alloc(struct istream_private *stream, size_t size) |
1055 | 0 | { |
1056 | 0 | size_t old_size, avail_size; |
1057 | |
|
1058 | 0 | (void)i_stream_try_alloc(stream, size, &avail_size); |
1059 | 0 | if (avail_size < size) { |
1060 | 0 | old_size = stream->buffer_size; |
1061 | 0 | stream->buffer_size = nearest_power(stream->pos + size); |
1062 | 0 | i_stream_w_buffer_realloc(stream, old_size); |
1063 | |
|
1064 | 0 | (void)i_stream_try_alloc(stream, size, &avail_size); |
1065 | 0 | i_assert(avail_size >= size); |
1066 | 0 | } |
1067 | 0 | return stream->w_buffer + stream->pos; |
1068 | 0 | } |
1069 | | |
1070 | | void i_stream_memarea_detach(struct istream_private *stream) |
1071 | 0 | { |
1072 | 0 | if (stream->memarea != NULL) { |
1073 | | /* Don't overwrite data in a snapshot. Allocate a new |
1074 | | buffer instead. */ |
1075 | 0 | memarea_unref(&stream->memarea); |
1076 | 0 | stream->buffer_size = 0; |
1077 | 0 | stream->buffer = NULL; |
1078 | 0 | stream->w_buffer = NULL; |
1079 | 0 | } |
1080 | 0 | } |
1081 | | |
1082 | | bool i_stream_add_data(struct istream *_stream, const unsigned char *data, |
1083 | | size_t size) |
1084 | 0 | { |
1085 | 0 | struct istream_private *stream = _stream->real_stream; |
1086 | 0 | size_t size2; |
1087 | |
|
1088 | 0 | if (size == 0) |
1089 | 0 | return TRUE; |
1090 | 0 | (void)i_stream_try_alloc(stream, size, &size2); |
1091 | 0 | if (size > size2) |
1092 | 0 | return FALSE; |
1093 | | |
1094 | 0 | memcpy(stream->w_buffer + stream->pos, data, size); |
1095 | 0 | stream->pos += size; |
1096 | 0 | return TRUE; |
1097 | 0 | } |
1098 | | |
1099 | | struct istream *i_stream_get_root_io(struct istream *stream) |
1100 | 0 | { |
1101 | 0 | struct istream_private *parent; |
1102 | |
|
1103 | 0 | while ((parent = i_stream_get_io_parent(stream->real_stream)) != NULL) { |
1104 | 0 | i_assert(stream->real_stream->io == NULL); |
1105 | 0 | stream = &parent->istream; |
1106 | 0 | } |
1107 | 0 | return stream; |
1108 | 0 | } |
1109 | | |
1110 | | static void i_stream_verify_pending_reachable(struct istream *owner) |
1111 | 0 | { |
1112 | 0 | const struct istream_reader *reader; |
1113 | | |
1114 | | /* The IO may still be added to owner later on. But if an istream that |
1115 | | is currently reading it already owns one, and it can't share it with |
1116 | | owner, this pending is lost. */ |
1117 | 0 | for (reader = istream_cur_reader; reader != NULL; reader = reader->prev) { |
1118 | 0 | struct istream *root; |
1119 | |
|
1120 | 0 | if (reader->ioloop != current_ioloop) { |
1121 | | /* Nested ioloop - the outer istreams aren't reading |
1122 | | this one. */ |
1123 | 0 | break; |
1124 | 0 | } |
1125 | 0 | if (reader->stream->real_stream->hidden_inputs != |
1126 | 0 | ISTREAM_HIDDEN_INPUTS_PANIC) |
1127 | 0 | continue; |
1128 | 0 | root = i_stream_get_root_io(reader->stream); |
1129 | 0 | if (root == owner || root->real_stream->io == NULL) |
1130 | 0 | continue; |
1131 | 0 | i_panic("i_stream_set_input_pending(%s) is lost: " |
1132 | 0 | "istream %s reads it and owns the ioloop IO", |
1133 | 0 | i_stream_get_name(owner), i_stream_get_name(root)); |
1134 | 0 | } |
1135 | 0 | } |
1136 | | |
1137 | | void i_stream_set_input_pending(struct istream *stream, bool pending) |
1138 | 0 | { |
1139 | 0 | if (!pending) |
1140 | 0 | return; |
1141 | | |
1142 | 0 | stream->real_stream->io_pending_until_read = TRUE; |
1143 | |
|
1144 | 0 | stream = i_stream_get_root_io(stream); |
1145 | 0 | if (stream->real_stream->io != NULL) |
1146 | 0 | io_set_pending(stream->real_stream->io); |
1147 | 0 | else { |
1148 | 0 | i_stream_verify_pending_reachable(stream); |
1149 | 0 | stream->real_stream->io_pending = TRUE; |
1150 | 0 | } |
1151 | 0 | } |
1152 | | |
1153 | | void i_stream_switch_ioloop_to(struct istream *stream, struct ioloop *ioloop) |
1154 | 0 | { |
1155 | 0 | io_stream_switch_ioloop_to(&stream->real_stream->iostream, ioloop); |
1156 | |
|
1157 | 0 | do { |
1158 | 0 | if (stream->real_stream->switch_ioloop_to != NULL) { |
1159 | 0 | stream->real_stream->switch_ioloop_to( |
1160 | 0 | stream->real_stream, ioloop); |
1161 | 0 | } |
1162 | 0 | if (stream->real_stream->io_parent != NULL) { |
1163 | | /* Switch also the hidden input istream, which isn't |
1164 | | reached by walking the istream-parents. */ |
1165 | 0 | i_stream_switch_ioloop_to( |
1166 | 0 | stream->real_stream->io_parent, ioloop); |
1167 | 0 | } |
1168 | 0 | stream = stream->real_stream->parent; |
1169 | 0 | } while (stream != NULL); |
1170 | 0 | } |
1171 | | |
1172 | | void i_stream_switch_ioloop(struct istream *stream) |
1173 | 0 | { |
1174 | 0 | i_stream_switch_ioloop_to(stream, current_ioloop); |
1175 | 0 | } |
1176 | | |
1177 | | bool i_stream_io_ever_added(struct istream *stream) |
1178 | 0 | { |
1179 | 0 | return i_stream_get_root_io(stream)->real_stream->io_ever_added; |
1180 | 0 | } |
1181 | | |
1182 | | void i_stream_set_io(struct istream *stream, struct io *io) |
1183 | 0 | { |
1184 | 0 | stream = i_stream_get_root_io(stream); |
1185 | |
|
1186 | 0 | i_assert(stream->real_stream->io == NULL); |
1187 | 0 | stream->real_stream->io = io; |
1188 | 0 | stream->real_stream->io_ever_added = TRUE; |
1189 | 0 | if (stream->real_stream->io_pending) { |
1190 | 0 | io_set_pending(io); |
1191 | 0 | stream->real_stream->io_pending = FALSE; |
1192 | 0 | } |
1193 | 0 | } |
1194 | | |
1195 | | void i_stream_unset_io(struct istream *stream, struct io *io) |
1196 | 0 | { |
1197 | 0 | stream = i_stream_get_root_io(stream); |
1198 | |
|
1199 | 0 | i_assert(stream->real_stream->io == io); |
1200 | 0 | if (io_is_pending(io)) |
1201 | 0 | stream->real_stream->io_pending = TRUE; |
1202 | 0 | stream->real_stream->io = NULL; |
1203 | 0 | } |
1204 | | |
1205 | | static void |
1206 | | i_stream_default_set_max_buffer_size(struct iostream_private *stream, |
1207 | | size_t max_size) |
1208 | 0 | { |
1209 | 0 | struct istream_private *_stream = |
1210 | 0 | container_of(stream, struct istream_private, iostream); |
1211 | |
|
1212 | 0 | _stream->max_buffer_size = max_size; |
1213 | 0 | if (_stream->parent != NULL) |
1214 | 0 | i_stream_set_max_buffer_size(_stream->parent, max_size); |
1215 | 0 | } |
1216 | | |
1217 | | static void i_stream_default_close(struct iostream_private *stream, |
1218 | | bool close_parent) |
1219 | 2.02k | { |
1220 | 2.02k | struct istream_private *_stream = |
1221 | 2.02k | container_of(stream, struct istream_private, iostream); |
1222 | | |
1223 | 2.02k | if (close_parent) |
1224 | 0 | i_stream_close(_stream->parent); |
1225 | 2.02k | } |
1226 | | |
1227 | | static void i_stream_default_destroy(struct iostream_private *stream) |
1228 | 1.94k | { |
1229 | 1.94k | struct istream_private *_stream = |
1230 | 1.94k | container_of(stream, struct istream_private, iostream); |
1231 | | |
1232 | 1.94k | i_stream_free_buffer(_stream); |
1233 | 1.94k | i_stream_unref(&_stream->parent); |
1234 | 1.94k | } |
1235 | | |
1236 | | static void |
1237 | | i_stream_default_seek_seekable(struct istream_private *stream, |
1238 | | uoff_t v_offset, bool mark ATTR_UNUSED) |
1239 | 0 | { |
1240 | 0 | stream->istream.v_offset = v_offset; |
1241 | 0 | stream->skip = stream->pos = 0; |
1242 | 0 | } |
1243 | | |
1244 | | void i_stream_default_seek_nonseekable(struct istream_private *stream, |
1245 | | uoff_t v_offset, bool mark ATTR_UNUSED) |
1246 | 1.18k | { |
1247 | 1.18k | size_t available; |
1248 | | |
1249 | 1.18k | if (stream->istream.v_offset > v_offset) |
1250 | 0 | i_panic("stream %s doesn't support seeking backwards", |
1251 | 0 | i_stream_get_name(&stream->istream)); |
1252 | | |
1253 | 1.18k | while (stream->istream.v_offset < v_offset) { |
1254 | 0 | (void)i_stream_read(&stream->istream); |
1255 | |
|
1256 | 0 | available = stream->pos - stream->skip; |
1257 | 0 | if (available == 0) { |
1258 | 0 | if (stream->istream.stream_errno != 0) { |
1259 | | /* read failed */ |
1260 | 0 | return; |
1261 | 0 | } |
1262 | 0 | io_stream_set_error(&stream->iostream, |
1263 | 0 | "Can't seek to offset %"PRIuUOFF_T |
1264 | 0 | ", because we have data only up to offset %" |
1265 | 0 | PRIuUOFF_T" (eof=%d)", v_offset, |
1266 | 0 | stream->istream.v_offset, stream->istream.eof ? 1 : 0); |
1267 | 0 | stream->istream.stream_errno = ESPIPE; |
1268 | 0 | return; |
1269 | 0 | } |
1270 | 0 | if (available <= v_offset - stream->istream.v_offset) |
1271 | 0 | i_stream_skip(&stream->istream, available); |
1272 | 0 | else { |
1273 | 0 | i_stream_skip(&stream->istream, |
1274 | 0 | v_offset - stream->istream.v_offset); |
1275 | 0 | } |
1276 | 0 | } |
1277 | 1.18k | } |
1278 | | |
1279 | | bool i_stream_nonseekable_try_seek(struct istream_private *stream, |
1280 | | uoff_t v_offset) |
1281 | 0 | { |
1282 | 0 | uoff_t start_offset = stream->istream.v_offset - stream->skip; |
1283 | |
|
1284 | 0 | if (v_offset < start_offset) { |
1285 | | /* have to seek backwards */ |
1286 | 0 | i_stream_seek(stream->parent, stream->parent_start_offset); |
1287 | 0 | stream->parent_expected_offset = stream->parent_start_offset; |
1288 | 0 | stream->skip = stream->pos = 0; |
1289 | 0 | stream->istream.v_offset = 0; |
1290 | 0 | stream->high_pos = 0; |
1291 | 0 | return FALSE; |
1292 | 0 | } |
1293 | | |
1294 | 0 | if (v_offset <= start_offset + stream->pos) { |
1295 | | /* seeking backwards within what's already cached */ |
1296 | 0 | stream->skip = v_offset - start_offset; |
1297 | 0 | stream->istream.v_offset = v_offset; |
1298 | 0 | if (stream->high_pos == 0) |
1299 | 0 | stream->high_pos = stream->pos; |
1300 | 0 | stream->pos = stream->skip; |
1301 | 0 | } else { |
1302 | | /* read forward */ |
1303 | 0 | i_stream_default_seek_nonseekable(stream, v_offset, FALSE); |
1304 | 0 | } |
1305 | 0 | return TRUE; |
1306 | 0 | } |
1307 | | |
1308 | | static int |
1309 | | seekable_i_stream_get_size(struct istream_private *stream) |
1310 | 0 | { |
1311 | 0 | if (stream->cached_stream_size == UOFF_T_MAX) { |
1312 | 0 | uoff_t old_offset = stream->istream.v_offset; |
1313 | 0 | ssize_t ret; |
1314 | |
|
1315 | 0 | do { |
1316 | 0 | i_stream_skip(&stream->istream, |
1317 | 0 | i_stream_get_data_size(&stream->istream)); |
1318 | 0 | } while ((ret = i_stream_read(&stream->istream)) > 0); |
1319 | 0 | i_assert(ret == -1); |
1320 | 0 | if (stream->istream.stream_errno != 0) |
1321 | 0 | return -1; |
1322 | | |
1323 | 0 | stream->cached_stream_size = stream->istream.v_offset; |
1324 | 0 | i_stream_seek(&stream->istream, old_offset); |
1325 | 0 | } |
1326 | 0 | stream->statbuf.st_size = stream->cached_stream_size; |
1327 | 0 | return 0; |
1328 | 0 | } |
1329 | | |
1330 | | static int |
1331 | | i_stream_default_stat(struct istream_private *stream, bool exact) |
1332 | 0 | { |
1333 | 0 | const struct stat *st; |
1334 | |
|
1335 | 0 | if (stream->parent == NULL) |
1336 | 0 | return stream->istream.stream_errno == 0 ? 0 : -1; |
1337 | | |
1338 | 0 | if (i_stream_stat(stream->parent, exact, &st) < 0) { |
1339 | 0 | stream->istream.stream_errno = stream->parent->stream_errno; |
1340 | 0 | return -1; |
1341 | 0 | } |
1342 | 0 | stream->statbuf = *st; |
1343 | 0 | if (exact && !stream->stream_size_passthrough) { |
1344 | | /* exact size is not known, even if parent returned something */ |
1345 | 0 | stream->statbuf.st_size = -1; |
1346 | 0 | if (stream->istream.seekable) { |
1347 | 0 | if (seekable_i_stream_get_size(stream) < 0) |
1348 | 0 | return -1; |
1349 | 0 | } |
1350 | 0 | } else { |
1351 | | /* When exact=FALSE always return the parent stat's size, even |
1352 | | if we know the exact value. This is necessary because |
1353 | | otherwise e.g. mbox code can see two different values and |
1354 | | think that the mbox file keeps changing. */ |
1355 | 0 | } |
1356 | 0 | return 0; |
1357 | 0 | } |
1358 | | |
1359 | | static int |
1360 | | i_stream_default_get_size(struct istream_private *stream, |
1361 | | bool exact, uoff_t *size_r) |
1362 | 0 | { |
1363 | 0 | if (stream->stat(stream, exact) < 0) |
1364 | 0 | return -1; |
1365 | 0 | if (stream->statbuf.st_size == -1) |
1366 | 0 | return 0; |
1367 | | |
1368 | 0 | *size_r = stream->statbuf.st_size; |
1369 | 0 | return 1; |
1370 | 0 | } |
1371 | | |
1372 | | void i_stream_init_parent(struct istream_private *_stream, |
1373 | | struct istream *parent) |
1374 | 0 | { |
1375 | 0 | _stream->access_counter = parent->real_stream->access_counter; |
1376 | 0 | _stream->parent = parent; |
1377 | 0 | _stream->parent_start_offset = parent->v_offset; |
1378 | 0 | _stream->parent_expected_offset = parent->v_offset; |
1379 | 0 | _stream->start_offset = parent->v_offset; |
1380 | | /* if parent stream is an istream-error, copy the error */ |
1381 | 0 | _stream->istream.stream_errno = parent->stream_errno; |
1382 | 0 | _stream->istream.eof = parent->eof; |
1383 | 0 | i_stream_ref(parent); |
1384 | 0 | } |
1385 | | |
1386 | | struct istream * |
1387 | | i_stream_create(struct istream_private *_stream, struct istream *parent, int fd, |
1388 | | enum istream_hidden_inputs hidden_inputs, |
1389 | | enum istream_create_flag flags) |
1390 | 2.95k | { |
1391 | 2.95k | bool noop_snapshot = (flags & ISTREAM_CREATE_FLAG_NOOP_SNAPSHOT) != 0; |
1392 | | |
1393 | | /* io_parent is what ISTREAM_HIDDEN_INPUTS_DECLARED declares, so one |
1394 | | without the other is a mistake in either direction. */ |
1395 | 2.95k | i_assert((_stream->io_parent != NULL) == |
1396 | 2.95k | (hidden_inputs == ISTREAM_HIDDEN_INPUTS_DECLARED)); |
1397 | 2.95k | _stream->hidden_inputs = hidden_inputs; |
1398 | | |
1399 | 2.95k | _stream->fd = fd; |
1400 | 2.95k | if (parent != NULL) |
1401 | 0 | i_stream_init_parent(_stream, parent); |
1402 | 2.95k | else if (_stream->memarea == NULL && !noop_snapshot) { |
1403 | | /* The stream has no parent and no memarea yet. We'll assume |
1404 | | that it wants to be using memareas for the reads. */ |
1405 | 1.94k | _stream->memarea = memarea_init_empty(); |
1406 | 1.94k | } |
1407 | 2.95k | _stream->istream.real_stream = _stream; |
1408 | | |
1409 | 2.95k | if (_stream->iostream.close == NULL) |
1410 | 2.02k | _stream->iostream.close = i_stream_default_close; |
1411 | 2.95k | if (_stream->iostream.destroy == NULL) |
1412 | 1.94k | _stream->iostream.destroy = i_stream_default_destroy; |
1413 | 2.95k | if (_stream->seek == NULL) { |
1414 | 0 | _stream->seek = _stream->istream.seekable ? |
1415 | 0 | i_stream_default_seek_seekable : |
1416 | 0 | i_stream_default_seek_nonseekable; |
1417 | 0 | } |
1418 | 2.95k | if (_stream->stat == NULL) |
1419 | 2.95k | _stream->stat = i_stream_default_stat; |
1420 | 2.95k | if (_stream->get_size == NULL) |
1421 | 2.95k | _stream->get_size = i_stream_default_get_size; |
1422 | 2.95k | if (_stream->snapshot == NULL) { |
1423 | 1.94k | _stream->snapshot = noop_snapshot ? |
1424 | 1.01k | i_stream_noop_snapshot : |
1425 | 1.94k | i_stream_default_snapshot; |
1426 | 1.94k | } |
1427 | 2.95k | if (_stream->iostream.set_max_buffer_size == NULL) { |
1428 | 1.01k | _stream->iostream.set_max_buffer_size = |
1429 | 1.01k | i_stream_default_set_max_buffer_size; |
1430 | 1.01k | } |
1431 | 2.95k | if (_stream->init_buffer_size == 0) |
1432 | 2.95k | _stream->init_buffer_size = I_STREAM_MIN_SIZE; |
1433 | | |
1434 | 2.95k | i_zero(&_stream->statbuf); |
1435 | 2.95k | _stream->statbuf.st_size = -1; |
1436 | 2.95k | _stream->statbuf.st_atime = |
1437 | 2.95k | _stream->statbuf.st_mtime = |
1438 | 2.95k | _stream->statbuf.st_ctime = ioloop_time; |
1439 | 2.95k | _stream->cached_stream_size = UOFF_T_MAX; |
1440 | | |
1441 | 2.95k | io_stream_init(&_stream->iostream); |
1442 | | |
1443 | 2.95k | if (_stream->istream.stream_errno != 0) |
1444 | 0 | _stream->istream.eof = TRUE; |
1445 | | |
1446 | 2.95k | return &_stream->istream; |
1447 | 2.95k | } |
1448 | | |
1449 | | struct istream *i_stream_create_error(int stream_errno) |
1450 | 0 | { |
1451 | 0 | struct istream_private *stream; |
1452 | |
|
1453 | 0 | stream = i_new(struct istream_private, 1); |
1454 | 0 | stream->istream.closed = TRUE; |
1455 | 0 | stream->istream.readable_fd = FALSE; |
1456 | 0 | stream->istream.blocking = TRUE; |
1457 | 0 | stream->istream.seekable = TRUE; |
1458 | 0 | stream->istream.eof = TRUE; |
1459 | 0 | stream->istream.stream_errno = stream_errno; |
1460 | | /* Nothing can ever actually be read from this stream, but set a |
1461 | | reasonable max_buffer_size anyway since some filter istreams don't |
1462 | | behave properly otherwise. */ |
1463 | 0 | stream->max_buffer_size = IO_BLOCK_SIZE; |
1464 | 0 | i_stream_create(stream, NULL, -1, |
1465 | 0 | ISTREAM_HIDDEN_INPUTS_NONE, 0); |
1466 | 0 | i_stream_set_name(&stream->istream, "(error)"); |
1467 | 0 | return &stream->istream; |
1468 | 0 | } |
1469 | | |
1470 | | struct istream * |
1471 | | i_stream_create_error_str(int stream_errno, const char *fmt, ...) |
1472 | 0 | { |
1473 | 0 | struct istream *input; |
1474 | 0 | va_list args; |
1475 | |
|
1476 | 0 | va_start(args, fmt); |
1477 | 0 | input = i_stream_create_error(stream_errno); |
1478 | 0 | io_stream_set_verror(&input->real_stream->iostream, fmt, args); |
1479 | | va_end(args); |
1480 | 0 | return input; |
1481 | 0 | } |