Coverage Report

Created: 2024-09-06 06:25

/src/dovecot/src/lib/istream.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2002-2018 Dovecot authors, see the included 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
0
{
14
0
  i_free(stream->real_stream->iostream.name);
15
0
  stream->real_stream->iostream.name = i_strdup(name);
16
0
}
17
18
const char *i_stream_get_name(struct istream *stream)
19
0
{
20
0
  i_assert(stream != NULL);
21
0
  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
0
  return stream->real_stream->iostream.name;
27
0
}
28
29
static void i_stream_close_full(struct istream *stream, bool close_parents)
30
0
{
31
0
  io_stream_close(&stream->real_stream->iostream, close_parents);
32
0
  stream->closed = TRUE;
33
34
0
  if (stream->stream_errno == 0)
35
0
    stream->stream_errno = EPIPE;
36
0
}
37
38
void i_stream_destroy(struct istream **stream)
39
0
{
40
0
  if (*stream == NULL)
41
0
    return;
42
43
0
  i_stream_close_full(*stream, FALSE);
44
0
  i_stream_unref(stream);
45
0
}
46
47
void i_stream_ref(struct istream *stream)
48
256k
{
49
256k
  io_stream_ref(&stream->real_stream->iostream);
50
256k
}
51
52
void i_stream_unref(struct istream **_stream)
53
291k
{
54
291k
  struct istream *stream = *_stream;
55
291k
  struct istream_private *rstream;
56
57
291k
  if (stream == NULL)
58
31.1k
    return;
59
60
260k
  *_stream = NULL;
61
260k
  rstream = stream->real_stream;
62
63
260k
  if (rstream->iostream.refcount > 1) {
64
256k
    if (!io_stream_unref(&rstream->iostream))
65
0
      i_unreached();
66
256k
  } else {
67
    /* The snapshot may contain pointers to the parent istreams.
68
       Free it before io_stream_unref() frees the parents. */
69
4.81k
    i_stream_snapshot_free(&rstream->prev_snapshot);
70
71
4.81k
    if (io_stream_unref(&rstream->iostream))
72
0
      i_unreached();
73
4.81k
    str_free(&rstream->line_str);
74
4.81k
    i_stream_unref(&rstream->parent);
75
4.81k
    io_stream_free(&rstream->iostream);
76
4.81k
  }
77
260k
}
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
0
{
96
0
  struct istream_private *_stream = stream->real_stream;
97
98
0
  return _stream->fd;
99
0
}
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
0
{
124
0
  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
0
  if (stream->stream_errno == 0)
130
0
    return stream->eof ? "EOF" : "<no error>";
131
132
0
  for (s = stream; s != NULL; s = s->real_stream->parent) {
133
0
    if (s->stream_errno == 0)
134
0
      break;
135
0
    if (s->real_stream->iostream.error != NULL)
136
0
      return s->real_stream->iostream.error;
137
0
  }
138
0
  return strerror(stream->stream_errno);
139
0
}
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
0
{
159
0
  io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
160
0
}
161
162
size_t i_stream_get_max_buffer_size(struct istream *stream)
163
0
{
164
0
  size_t max_size = 0;
165
166
0
  do {
167
0
    if (max_size < stream->real_stream->max_buffer_size)
168
0
      max_size = stream->real_stream->max_buffer_size;
169
0
    stream = stream->real_stream->parent;
170
0
  } while (stream != NULL);
171
0
  return max_size;
172
0
}
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
27.0k
{
204
27.0k
  if (stream->parent == NULL)
205
27.0k
    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
27.0k
}
212
213
static bool snapshot_has_memarea(struct istream_snapshot *snapshot,
214
         struct memarea *memarea)
215
42.3k
{
216
42.3k
  if (snapshot->old_memarea == memarea)
217
0
    return TRUE;
218
42.3k
  if (snapshot->prev_snapshot != NULL)
219
25.2k
    return snapshot_has_memarea(snapshot->prev_snapshot, memarea);
220
17.0k
  return FALSE;
221
42.3k
}
222
223
struct istream_snapshot *
224
i_stream_default_snapshot(struct istream_private *stream,
225
        struct istream_snapshot *prev_snapshot)
226
21.5k
{
227
21.5k
  struct istream_snapshot *snapshot;
228
229
21.5k
  if (stream->memarea != NULL) {
230
21.5k
    if (prev_snapshot != NULL) {
231
17.0k
      if (snapshot_has_memarea(prev_snapshot, stream->memarea))
232
0
        return prev_snapshot;
233
17.0k
    }
234
    /* This stream has a memarea. Reference it, so we can later on
235
       rollback if needed. */
236
21.5k
    snapshot = i_new(struct istream_snapshot, 1);
237
21.5k
    snapshot->old_memarea = stream->memarea;
238
21.5k
    snapshot->prev_snapshot = prev_snapshot;
239
21.5k
    memarea_ref(snapshot->old_memarea);
240
21.5k
    return snapshot;
241
21.5k
  }
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
31.1k
{
260
31.1k
  struct istream_snapshot *snapshot = *_snapshot;
261
262
31.1k
  if (*_snapshot == NULL)
263
9.62k
    return;
264
21.5k
  *_snapshot = NULL;
265
266
21.5k
  i_stream_snapshot_free(&snapshot->prev_snapshot);
267
21.5k
  if (snapshot->free != NULL)
268
0
    snapshot->free(snapshot);
269
21.5k
  else {
270
21.5k
    if (snapshot->old_memarea != NULL)
271
21.5k
      memarea_unref(&snapshot->old_memarea);
272
21.5k
    i_stream_unref(&snapshot->istream);
273
21.5k
    i_free(snapshot);
274
21.5k
  }
275
21.5k
}
276
277
static struct istream_snapshot *
278
i_stream_noop_snapshot(struct istream_private *stream ATTR_UNUSED,
279
           struct istream_snapshot *prev_snapshot)
280
0
{
281
0
  return prev_snapshot;
282
0
}
283
284
ssize_t i_stream_read(struct istream *stream)
285
27.0k
{
286
27.0k
  struct istream_private *_stream = stream->real_stream;
287
27.0k
  ssize_t ret;
288
#ifdef DEBUG
289
  unsigned char prev_buf[4];
290
  const unsigned char *prev_data = _stream->buffer;
291
  size_t prev_skip = _stream->skip, prev_pos = _stream->pos;
292
  bool invalid = i_stream_is_buffer_invalid(_stream);
293
294
  i_assert(prev_skip <= prev_pos);
295
  size_t prev_size = prev_pos - prev_skip;
296
  if (invalid)
297
    ;
298
  else if (prev_size > 4) {
299
    memcpy(prev_buf, prev_data + prev_skip, 2);
300
    memcpy(prev_buf+2, prev_data + prev_pos - 2, 2);
301
  } else if (prev_size > 0) {
302
    memcpy(prev_buf, prev_data + prev_skip, prev_size);
303
  }
304
#endif
305
306
27.0k
  if (_stream->skip != _stream->pos || _stream->prev_snapshot != NULL) {
307
21.5k
    _stream->prev_snapshot =
308
21.5k
      _stream->snapshot(_stream, _stream->prev_snapshot);
309
21.5k
  }
310
27.0k
  ret = i_stream_read_memarea(stream);
311
27.0k
  if (ret > 0)
312
4.81k
    i_stream_snapshot_free(&_stream->prev_snapshot);
313
#ifdef DEBUG
314
  else if (!invalid) {
315
    i_assert((_stream->pos - _stream->skip) == (prev_pos - prev_skip) ||
316
       prev_pos == prev_skip);
317
    if (prev_data == NULL)
318
      i_assert(prev_pos == prev_skip);
319
    else if (prev_pos - prev_skip <= 4)
320
      i_assert(memcmp(prev_buf, prev_data + prev_skip, prev_pos - prev_skip) == 0);
321
    else {
322
      i_assert(memcmp(prev_buf, prev_data + prev_skip, 2) == 0);
323
      i_assert(memcmp(prev_buf+2, prev_data + prev_pos - 2, 2) == 0);
324
    }
325
  }
326
#endif
327
27.0k
  return ret;
328
27.0k
}
329
330
ssize_t i_stream_read_memarea(struct istream *stream)
331
27.0k
{
332
27.0k
  struct istream_private *_stream = stream->real_stream;
333
27.0k
  size_t old_size;
334
27.0k
  ssize_t ret;
335
336
27.0k
  if (unlikely(stream->closed || stream->stream_errno != 0)) {
337
0
    stream->eof = TRUE;
338
0
    errno = stream->stream_errno;
339
0
    return -1;
340
0
  }
341
342
27.0k
  stream->eof = FALSE;
343
344
27.0k
  if (_stream->parent != NULL)
345
0
    i_stream_seek(_stream->parent, _stream->parent_expected_offset);
346
347
27.0k
  old_size = _stream->pos - _stream->skip;
348
27.0k
  if (_stream->pos < _stream->high_pos) {
349
    /* we're here because we seeked back within the read buffer. */
350
0
    ret = _stream->high_pos - _stream->pos;
351
0
    _stream->pos = _stream->high_pos;
352
0
    _stream->high_pos = 0;
353
27.0k
  } else {
354
27.0k
    _stream->high_pos = 0;
355
27.0k
    ret = _stream->read(_stream);
356
27.0k
  }
357
27.0k
  i_assert(old_size <= _stream->pos - _stream->skip);
358
27.0k
  switch (ret) {
359
0
  case -2:
360
0
    i_assert(_stream->skip != _stream->pos);
361
0
    break;
362
22.1k
  case -1:
363
22.1k
    if (stream->stream_errno != 0) {
364
      /* error handling should be easier if we now just
365
         assume the stream is now at EOF */
366
0
      stream->eof = TRUE;
367
0
      errno = stream->stream_errno;
368
22.1k
    } else {
369
22.1k
      i_assert(stream->eof);
370
22.1k
      i_assert(old_size == _stream->pos - _stream->skip);
371
22.1k
    }
372
22.1k
    break;
373
22.1k
  case 0:
374
0
    i_assert(!stream->blocking);
375
0
    break;
376
4.81k
  default:
377
4.81k
    i_assert(ret > 0);
378
4.81k
    i_assert(_stream->skip < _stream->pos);
379
4.81k
    i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
380
4.81k
    _stream->last_read_timeval = ioloop_timeval;
381
4.81k
    break;
382
27.0k
  }
383
384
27.0k
  if (stream->stream_errno != 0) {
385
    /* error handling should be easier if we now just
386
       assume the stream is now at EOF. Note that we could get here
387
       even if read() didn't return -1, although that's a little
388
       bit sloppy istream implementation. */
389
0
    stream->eof = TRUE;
390
0
  }
391
392
27.0k
  i_stream_update(_stream);
393
  /* verify that parents' access_counters are valid. the parent's
394
     i_stream_read() should guarantee this. */
395
27.0k
  i_assert(!i_stream_is_buffer_invalid(_stream));
396
27.0k
  return ret;
397
27.0k
}
398
399
int i_stream_read_more_memarea(struct istream *stream,
400
             const unsigned char **data_r, size_t *size_r)
401
0
{
402
0
  *data_r = i_stream_get_data(stream, size_r);
403
0
  if (*size_r > 0)
404
0
    return 1;
405
406
0
  int ret = i_stream_read_memarea(stream);
407
0
  *data_r = i_stream_get_data(stream, size_r);
408
0
  return ret;
409
0
}
410
411
void i_stream_get_last_read_time(struct istream *stream, struct timeval *tv_r)
412
0
{
413
0
  *tv_r = stream->real_stream->last_read_timeval;
414
0
}
415
416
ssize_t i_stream_read_copy_from_parent(struct istream *istream)
417
0
{
418
0
  struct istream_private *stream = istream->real_stream;
419
0
  size_t pos;
420
0
  ssize_t ret;
421
422
0
  stream->pos -= stream->skip;
423
0
  stream->skip = 0;
424
425
0
  stream->buffer = i_stream_get_data(stream->parent, &pos);
426
0
  if (pos > stream->pos)
427
0
    ret = 0;
428
0
  else do {
429
0
    ret = i_stream_read_memarea(stream->parent);
430
0
    stream->istream.stream_errno = stream->parent->stream_errno;
431
0
    stream->istream.eof = stream->parent->eof;
432
0
    stream->buffer = i_stream_get_data(stream->parent, &pos);
433
    /* check again, in case the parent stream had been seeked
434
       backwards and the previous read() didn't get us far
435
       enough. */
436
0
  } while (pos <= stream->pos && ret > 0);
437
0
  if (ret == -2) {
438
0
    i_stream_update(stream);
439
0
    return -2;
440
0
  }
441
442
0
  ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
443
0
    (ret == 0 ? 0 : -1);
444
0
  stream->pos = pos;
445
0
  i_assert(ret != -1 || stream->istream.eof ||
446
0
     stream->istream.stream_errno != 0);
447
0
  i_stream_update(stream);
448
0
  return ret;
449
0
}
450
451
void i_stream_free_buffer(struct istream_private *stream)
452
4.81k
{
453
4.81k
  if (stream->memarea != NULL) {
454
4.81k
    memarea_unref(&stream->memarea);
455
4.81k
    stream->w_buffer = NULL;
456
4.81k
  } else if (stream->w_buffer != NULL) {
457
0
    i_free_and_null(stream->w_buffer);
458
0
  } else {
459
    /* don't know how to free it */
460
0
    return;
461
0
  }
462
4.81k
  stream->buffer_size = 0;
463
4.81k
}
464
465
void i_stream_skip(struct istream *stream, uoff_t count)
466
1.09M
{
467
1.09M
  struct istream_private *_stream = stream->real_stream;
468
1.09M
  size_t data_size;
469
470
1.09M
  data_size = _stream->pos - _stream->skip;
471
1.09M
  if (count <= data_size) {
472
    /* within buffer */
473
1.09M
    stream->v_offset += count;
474
1.09M
    _stream->skip += count;
475
1.09M
    if (_stream->nonpersistent_buffers &&
476
1.09M
        _stream->skip == _stream->pos) {
477
0
      _stream->skip = _stream->pos = 0;
478
0
      i_stream_free_buffer(_stream);
479
0
    }
480
1.09M
    return;
481
1.09M
  }
482
483
  /* have to seek forward */
484
0
  count -= data_size;
485
0
  _stream->skip = _stream->pos;
486
0
  stream->v_offset += data_size;
487
488
0
  if (unlikely(stream->closed || stream->stream_errno != 0))
489
0
    return;
490
491
0
  _stream->seek(_stream, stream->v_offset + count, FALSE);
492
0
}
493
494
static bool i_stream_can_optimize_seek(struct istream_private *stream)
495
0
{
496
0
  if (stream->parent == NULL)
497
0
    return TRUE;
498
499
  /* use the fast route only if the parent stream hasn't been changed */
500
0
  if (stream->access_counter !=
501
0
      stream->parent->real_stream->access_counter)
502
0
    return FALSE;
503
504
0
  return i_stream_can_optimize_seek(stream->parent->real_stream);
505
0
}
506
507
void i_stream_seek(struct istream *stream, uoff_t v_offset)
508
0
{
509
0
  struct istream_private *_stream = stream->real_stream;
510
511
0
  if (v_offset >= stream->v_offset &&
512
0
      i_stream_can_optimize_seek(_stream))
513
0
    i_stream_skip(stream, v_offset - stream->v_offset);
514
0
  else {
515
0
    if (unlikely(stream->closed || stream->stream_errno != 0)) {
516
0
      stream->eof = TRUE;
517
0
      return;
518
0
    }
519
0
    stream->eof = FALSE;
520
0
    _stream->seek(_stream, v_offset, FALSE);
521
0
  }
522
0
  i_stream_update(_stream);
523
0
}
524
525
void i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
526
0
{
527
0
  struct istream_private *_stream = stream->real_stream;
528
529
0
  if (unlikely(stream->closed || stream->stream_errno != 0))
530
0
    return;
531
532
0
  stream->eof = FALSE;
533
0
  _stream->seek(_stream, v_offset, TRUE);
534
0
  i_stream_update(_stream);
535
0
}
536
537
void i_stream_sync(struct istream *stream)
538
0
{
539
0
  struct istream_private *_stream = stream->real_stream;
540
541
0
  if (unlikely(stream->closed || stream->stream_errno != 0))
542
0
    return;
543
544
0
  if (_stream->sync != NULL) {
545
0
    _stream->sync(_stream);
546
0
    i_stream_update(_stream);
547
0
  }
548
0
}
549
550
int i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
551
0
{
552
0
  struct istream_private *_stream = stream->real_stream;
553
554
0
  if (unlikely(stream->closed || stream->stream_errno != 0))
555
0
    return -1;
556
557
0
  if (_stream->stat(_stream, exact) < 0) {
558
0
    stream->eof = TRUE;
559
0
    return -1;
560
0
  }
561
0
  *st_r = &_stream->statbuf;
562
0
  return 0;
563
0
}
564
565
int i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
566
0
{
567
0
  struct istream_private *_stream = stream->real_stream;
568
569
0
  if (unlikely(stream->closed || stream->stream_errno != 0))
570
0
    return -1;
571
572
0
  int ret;
573
0
  if ((ret = _stream->get_size(_stream, exact, size_r)) < 0)
574
0
    stream->eof = TRUE;
575
0
  return ret;
576
0
}
577
578
bool i_stream_have_bytes_left(struct istream *stream)
579
0
{
580
0
  return i_stream_get_data_size(stream) > 0 || !stream->eof;
581
0
}
582
583
bool i_stream_read_eof(struct istream *stream)
584
0
{
585
0
  if (i_stream_get_data_size(stream) == 0)
586
0
    (void)i_stream_read(stream);
587
0
  return !i_stream_have_bytes_left(stream);
588
0
}
589
590
uoff_t i_stream_get_absolute_offset(struct istream *stream)
591
0
{
592
0
  uoff_t abs_offset = stream->v_offset;
593
0
  while (stream != NULL) {
594
0
    abs_offset += stream->real_stream->start_offset;
595
0
    stream = stream->real_stream->parent;
596
0
  }
597
0
  return abs_offset;
598
0
}
599
600
static char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
601
0
{
602
0
  char *ret;
603
0
  size_t end;
604
605
0
  if (i > stream->skip && stream->buffer[i-1] == '\r') {
606
0
    end = i - 1;
607
0
    stream->line_crlf = TRUE;
608
0
  } else {
609
0
    end = i;
610
0
    stream->line_crlf = FALSE;
611
0
  }
612
613
0
  if (stream->buffer == stream->w_buffer &&
614
0
      end < stream->buffer_size) {
615
    /* modify the buffer directly */
616
0
    stream->w_buffer[end] = '\0';
617
0
    ret = (char *)stream->w_buffer + stream->skip;
618
0
  } else {
619
    /* use a temporary string to return it */
620
0
    if (stream->line_str == NULL)
621
0
      stream->line_str = str_new(default_pool, 256);
622
0
    str_truncate(stream->line_str, 0);
623
0
    if (stream->skip < end)
624
0
      str_append_data(stream->line_str, stream->buffer + stream->skip,
625
0
          end - stream->skip);
626
0
    ret = str_c_modifiable(stream->line_str);
627
0
  }
628
629
0
  if (i < stream->pos)
630
0
    i++;
631
0
  stream->istream.v_offset += i - stream->skip;
632
0
  stream->skip = i;
633
0
  return ret;
634
0
}
635
636
static char *i_stream_last_line(struct istream_private *_stream)
637
0
{
638
0
  if (_stream->istream.eof && _stream->skip != _stream->pos &&
639
0
      _stream->return_nolf_line) {
640
    /* the last line is missing LF and we want to return it. */
641
0
    return i_stream_next_line_finish(_stream, _stream->pos);
642
0
  }
643
0
  return NULL;
644
0
}
645
646
char *i_stream_next_line(struct istream *stream)
647
0
{
648
0
  struct istream_private *_stream = stream->real_stream;
649
0
  const unsigned char *pos;
650
651
0
  if (_stream->skip >= _stream->pos)
652
0
    return NULL;
653
654
0
  pos = memchr(_stream->buffer + _stream->skip, '\n',
655
0
         _stream->pos - _stream->skip);
656
0
  if (pos != NULL) {
657
0
    return i_stream_next_line_finish(_stream,
658
0
             pos - _stream->buffer);
659
0
  } else {
660
0
    return i_stream_last_line(_stream);
661
0
  }
662
0
}
663
664
char *i_stream_read_next_line(struct istream *stream)
665
0
{
666
0
  char *line;
667
668
0
  for (;;) {
669
0
    line = i_stream_next_line(stream);
670
0
    if (line != NULL)
671
0
      break;
672
673
0
    switch (i_stream_read(stream)) {
674
0
    case -2:
675
0
      io_stream_set_error(&stream->real_stream->iostream,
676
0
        "Line is too long (over %zu"
677
0
        " bytes at offset %"PRIuUOFF_T")",
678
0
        i_stream_get_data_size(stream), stream->v_offset);
679
0
      stream->stream_errno = errno = ENOBUFS;
680
0
      stream->eof = TRUE;
681
0
      return NULL;
682
0
    case -1:
683
0
      return i_stream_last_line(stream->real_stream);
684
0
    case 0:
685
0
      return NULL;
686
0
    }
687
0
  }
688
0
  return line;
689
0
}
690
691
bool i_stream_last_line_crlf(struct istream *stream)
692
0
{
693
0
  return stream->real_stream->line_crlf;
694
0
}
695
696
static bool i_stream_is_buffer_invalid(const struct istream_private *stream)
697
2.28M
{
698
2.28M
  if (stream->parent == NULL) {
699
    /* the buffer can't point to parent, because it doesn't exist */
700
2.28M
    return FALSE;
701
2.28M
  }
702
0
  if (stream->w_buffer != NULL) {
703
    /* we can pretty safely assume that the stream is using its
704
       own private buffer, so it can never become invalid. */
705
0
    return FALSE;
706
0
  }
707
0
  if (stream->access_counter !=
708
0
      stream->parent->real_stream->access_counter) {
709
    /* parent has been modified behind this stream, we can't trust
710
       that our buffer is valid */
711
0
    return TRUE;
712
0
  }
713
0
  return i_stream_is_buffer_invalid(stream->parent->real_stream);
714
0
}
715
716
const unsigned char *
717
i_stream_get_data(struct istream *stream, size_t *size_r)
718
2.29M
{
719
2.29M
  struct istream_private *_stream = stream->real_stream;
720
721
2.29M
  if (_stream->skip >= _stream->pos) {
722
31.3k
    *size_r = 0;
723
31.3k
    return uchar_empty_ptr;
724
31.3k
  }
725
726
2.26M
  if (unlikely(i_stream_is_buffer_invalid(_stream))) {
727
    /* This stream may be using parent's buffer directly as
728
       _stream->buffer, but the parent stream has already been
729
       modified indirectly. This means that the buffer might no
730
       longer point to where we assume it points to. So we'll
731
       just return the stream as empty until it's read again.
732
733
       It's a bit ugly to suddenly drop data from the stream that
734
       was already read, but since this happens only with shared
735
       parent istreams the caller is hopefully aware enough that
736
       something like this might happen. The other solutions would
737
       be to a) try to automatically read the data back (but we
738
       can't handle errors..) or b) always copy data to stream's
739
       own buffer instead of pointing to parent's buffer (but this
740
       causes data copying that is nearly always unnecessary). */
741
0
    *size_r = 0;
742
    /* if we had already read until EOF, mark the stream again as
743
       not being at the end of file. */
744
0
    if (stream->stream_errno == 0) {
745
0
      _stream->skip = _stream->pos = 0;
746
0
      stream->eof = FALSE;
747
0
    }
748
0
    return uchar_empty_ptr;
749
0
  }
750
751
2.26M
        *size_r = _stream->pos - _stream->skip;
752
2.26M
        return _stream->buffer + _stream->skip;
753
2.26M
}
754
755
size_t i_stream_get_data_size(struct istream *stream)
756
0
{
757
0
  size_t size;
758
759
0
  (void)i_stream_get_data(stream, &size);
760
0
  return size;
761
0
}
762
763
unsigned char *i_stream_get_modifiable_data(struct istream *stream,
764
              size_t *size_r)
765
0
{
766
0
  struct istream_private *_stream = stream->real_stream;
767
768
0
  if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
769
0
    *size_r = 0;
770
0
    return NULL;
771
0
  }
772
773
0
        *size_r = _stream->pos - _stream->skip;
774
0
        return _stream->w_buffer + _stream->skip;
775
0
}
776
777
int i_stream_read_data(struct istream *stream, const unsigned char **data_r,
778
           size_t *size_r, size_t threshold)
779
2.09M
{
780
2.09M
  ssize_t ret = 0;
781
2.09M
  bool read_more = FALSE;
782
783
2.09M
  do {
784
2.09M
    *data_r = i_stream_get_data(stream, size_r);
785
2.09M
    if (*size_r > threshold)
786
2.06M
      return 1;
787
788
    /* we need more data */
789
27.0k
    ret = i_stream_read(stream);
790
27.0k
    if (ret > 0)
791
4.81k
      read_more = TRUE;
792
27.0k
  } while (ret > 0);
793
794
22.1k
  *data_r = i_stream_get_data(stream, size_r);
795
22.1k
  if (ret == -2)
796
0
    return -2;
797
798
22.1k
  if (ret == 0) {
799
    /* need to read more */
800
0
    i_assert(!stream->blocking);
801
0
    return 0;
802
0
  }
803
22.1k
  if (stream->stream_errno == 0 && read_more) {
804
    /* we read at least some new data */
805
0
    return 0;
806
0
  }
807
22.1k
  return -1;
808
22.1k
}
809
810
int i_stream_read_limited(struct istream *stream, const unsigned char **data_r,
811
        size_t *size_r, size_t limit)
812
0
{
813
0
  struct istream_private *_stream = stream->real_stream;
814
0
  int ret;
815
816
0
  *data_r = i_stream_get_data(stream, size_r);
817
0
  if (*size_r >= limit) {
818
0
    *size_r = limit;
819
0
    return 1;
820
0
  }
821
822
0
  _stream->data_limit = limit;
823
0
  ret = i_stream_read_more(stream, data_r, size_r);
824
0
  _stream->data_limit = 0;
825
826
0
  if (*size_r >= limit)
827
0
    *size_r = limit;
828
0
  return ret;
829
0
}
830
831
void i_stream_compress(struct istream_private *stream)
832
0
{
833
0
  i_assert(stream->memarea == NULL ||
834
0
     memarea_get_refcount(stream->memarea) == 1);
835
836
0
  if (stream->skip != stream->pos) {
837
0
    memmove(stream->w_buffer, stream->w_buffer + stream->skip,
838
0
      stream->pos - stream->skip);
839
0
  }
840
0
  stream->pos -= stream->skip;
841
842
0
  stream->skip = 0;
843
0
}
844
845
static void i_stream_w_buffer_free(void *buf)
846
0
{
847
0
  i_free(buf);
848
0
}
849
850
static void
851
i_stream_w_buffer_realloc(struct istream_private *stream, size_t old_size)
852
0
{
853
0
  void *new_buffer;
854
855
0
  if (stream->memarea != NULL &&
856
0
      memarea_get_refcount(stream->memarea) == 1) {
857
    /* Nobody else is referencing the memarea.
858
       We can just reallocate it. */
859
0
    memarea_free_without_callback(&stream->memarea);
860
0
    new_buffer = i_realloc(stream->w_buffer, old_size,
861
0
               stream->buffer_size);
862
0
  } else {
863
0
    new_buffer = i_malloc(stream->buffer_size);
864
0
    if (old_size > 0) {
865
0
      i_assert(stream->w_buffer != NULL);
866
0
      memcpy(new_buffer, stream->w_buffer, old_size);
867
0
    }
868
0
    if (stream->memarea != NULL)
869
0
      memarea_unref(&stream->memarea);
870
0
  }
871
872
0
  stream->w_buffer = new_buffer;
873
0
  stream->buffer = new_buffer;
874
875
0
  stream->memarea = memarea_init(stream->w_buffer, stream->buffer_size,
876
0
               i_stream_w_buffer_free, new_buffer);
877
0
}
878
879
void i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
880
0
{
881
0
  size_t old_size, max_size;
882
883
0
  old_size = stream->buffer_size;
884
885
0
  stream->buffer_size = stream->pos + bytes;
886
0
  if (stream->buffer_size <= stream->init_buffer_size)
887
0
    stream->buffer_size = stream->init_buffer_size;
888
0
  else
889
0
    stream->buffer_size = nearest_power(stream->buffer_size);
890
891
0
  max_size = i_stream_get_max_buffer_size(&stream->istream);
892
0
  i_assert(max_size > 0);
893
0
  if (stream->buffer_size > max_size)
894
0
    stream->buffer_size = max_size;
895
896
0
  if (stream->buffer_size <= old_size)
897
0
    stream->buffer_size = old_size;
898
0
  else
899
0
    i_stream_w_buffer_realloc(stream, old_size);
900
0
}
901
902
bool i_stream_try_alloc(struct istream_private *stream,
903
      size_t wanted_size, size_t *size_r)
904
0
{
905
0
  i_assert(wanted_size > 0);
906
0
  i_assert(stream->buffer_size >= stream->pos);
907
908
0
  if (wanted_size > stream->buffer_size - stream->pos) {
909
0
    if (stream->skip > 0) {
910
      /* remove the unused bytes from beginning of buffer */
911
0
      if (stream->memarea != NULL &&
912
0
          memarea_get_refcount(stream->memarea) > 1) {
913
        /* The memarea is still referenced. We can't
914
           overwrite data until extra references are
915
           gone. */
916
0
        i_stream_w_buffer_realloc(stream, stream->buffer_size);
917
0
      }
918
0
      i_stream_compress(stream);
919
0
    } else if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream)) {
920
      /* buffer is full - grow it */
921
0
      i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
922
0
    }
923
0
  }
924
925
0
  if (stream->data_limit == 0 ||
926
0
      (stream->buffer_size - stream->skip) < stream->data_limit)
927
0
    *size_r = stream->buffer_size - stream->pos;
928
0
  else {
929
0
    size_t buffered = (stream->pos - stream->skip);
930
931
0
    if (buffered >= stream->data_limit)
932
0
      *size_r = 0;
933
0
    else
934
0
      *size_r = stream->data_limit - buffered;
935
0
  }
936
0
  i_assert(stream->w_buffer != NULL || *size_r == 0);
937
0
  return *size_r > 0;
938
0
}
939
940
bool ATTR_NOWARN_UNUSED_RESULT
941
i_stream_try_alloc_avoid_compress(struct istream_private *stream,
942
          size_t wanted_size, size_t *size_r)
943
0
{
944
0
  size_t old_skip = stream->skip;
945
946
  /* try first with skip=0, so no compression is done */
947
0
  stream->skip = 0;
948
0
  bool ret = i_stream_try_alloc(stream, wanted_size, size_r);
949
0
  stream->skip = old_skip;
950
0
  if (ret || old_skip == 0)
951
0
    return ret;
952
  /* it's full. try with compression. */
953
0
  return i_stream_try_alloc(stream, wanted_size, size_r);
954
0
}
955
956
void *i_stream_alloc(struct istream_private *stream, size_t size)
957
0
{
958
0
  size_t old_size, avail_size;
959
960
0
  (void)i_stream_try_alloc(stream, size, &avail_size);
961
0
  if (avail_size < size) {
962
0
    old_size = stream->buffer_size;
963
0
    stream->buffer_size = nearest_power(stream->pos + size);
964
0
    i_stream_w_buffer_realloc(stream, old_size);
965
966
0
    (void)i_stream_try_alloc(stream, size, &avail_size);
967
0
    i_assert(avail_size >= size);
968
0
  }
969
0
  return stream->w_buffer + stream->pos;
970
0
}
971
972
void i_stream_memarea_detach(struct istream_private *stream)
973
0
{
974
0
  if (stream->memarea != NULL) {
975
    /* Don't overwrite data in a snapshot. Allocate a new
976
       buffer instead. */
977
0
    memarea_unref(&stream->memarea);
978
0
    stream->buffer_size = 0;
979
0
    stream->buffer = NULL;
980
0
    stream->w_buffer = NULL;
981
0
  }
982
0
}
983
984
bool i_stream_add_data(struct istream *_stream, const unsigned char *data,
985
           size_t size)
986
0
{
987
0
  struct istream_private *stream = _stream->real_stream;
988
0
  size_t size2;
989
990
0
  if (size == 0)
991
0
    return TRUE;
992
0
  (void)i_stream_try_alloc(stream, size, &size2);
993
0
  if (size > size2)
994
0
    return FALSE;
995
996
0
  memcpy(stream->w_buffer + stream->pos, data, size);
997
0
  stream->pos += size;
998
0
  return TRUE;
999
0
}
1000
1001
struct istream *i_stream_get_root_io(struct istream *stream)
1002
0
{
1003
0
  while (stream->real_stream->parent != NULL) {
1004
0
    i_assert(stream->real_stream->io == NULL);
1005
0
    stream = stream->real_stream->parent;
1006
0
  }
1007
0
  return stream;
1008
0
}
1009
1010
void i_stream_set_input_pending(struct istream *stream, bool pending)
1011
0
{
1012
0
  if (!pending)
1013
0
    return;
1014
1015
0
  stream = i_stream_get_root_io(stream);
1016
0
  if (stream->real_stream->io != NULL)
1017
0
    io_set_pending(stream->real_stream->io);
1018
0
  else
1019
0
    stream->real_stream->io_pending = TRUE;
1020
0
}
1021
1022
void i_stream_switch_ioloop_to(struct istream *stream, struct ioloop *ioloop)
1023
0
{
1024
0
  io_stream_switch_ioloop_to(&stream->real_stream->iostream, ioloop);
1025
1026
0
  do {
1027
0
    if (stream->real_stream->switch_ioloop_to != NULL) {
1028
0
      stream->real_stream->switch_ioloop_to(
1029
0
        stream->real_stream, ioloop);
1030
0
    }
1031
0
    stream = stream->real_stream->parent;
1032
0
  } while (stream != NULL);
1033
0
}
1034
1035
void i_stream_switch_ioloop(struct istream *stream)
1036
0
{
1037
0
  i_stream_switch_ioloop_to(stream, current_ioloop);
1038
0
}
1039
1040
void i_stream_set_io(struct istream *stream, struct io *io)
1041
0
{
1042
0
  stream = i_stream_get_root_io(stream);
1043
1044
0
  i_assert(stream->real_stream->io == NULL);
1045
0
  stream->real_stream->io = io;
1046
0
  if (stream->real_stream->io_pending) {
1047
0
    io_set_pending(io);
1048
0
    stream->real_stream->io_pending = FALSE;
1049
0
  }
1050
0
}
1051
1052
void i_stream_unset_io(struct istream *stream, struct io *io)
1053
0
{
1054
0
  stream = i_stream_get_root_io(stream);
1055
1056
0
  i_assert(stream->real_stream->io == io);
1057
0
  if (io_is_pending(io))
1058
0
    stream->real_stream->io_pending = TRUE;
1059
0
  stream->real_stream->io = NULL;
1060
0
}
1061
1062
static void
1063
i_stream_default_set_max_buffer_size(struct iostream_private *stream,
1064
             size_t max_size)
1065
0
{
1066
0
  struct istream_private *_stream =
1067
0
    container_of(stream, struct istream_private, iostream);
1068
1069
0
  _stream->max_buffer_size = max_size;
1070
0
  if (_stream->parent != NULL)
1071
0
    i_stream_set_max_buffer_size(_stream->parent, max_size);
1072
0
}
1073
1074
static void i_stream_default_close(struct iostream_private *stream,
1075
           bool close_parent)
1076
4.81k
{
1077
4.81k
  struct istream_private *_stream =
1078
4.81k
    container_of(stream, struct istream_private, iostream);
1079
1080
4.81k
  if (close_parent)
1081
0
    i_stream_close(_stream->parent);
1082
4.81k
}
1083
1084
static void i_stream_default_destroy(struct iostream_private *stream)
1085
4.81k
{
1086
4.81k
  struct istream_private *_stream =
1087
4.81k
    container_of(stream, struct istream_private, iostream);
1088
1089
4.81k
  i_stream_free_buffer(_stream);
1090
4.81k
  i_stream_unref(&_stream->parent);
1091
4.81k
}
1092
1093
static void
1094
i_stream_default_seek_seekable(struct istream_private *stream,
1095
             uoff_t v_offset, bool mark ATTR_UNUSED)
1096
0
{
1097
0
  stream->istream.v_offset = v_offset;
1098
0
  stream->skip = stream->pos = 0;
1099
0
}
1100
1101
void i_stream_default_seek_nonseekable(struct istream_private *stream,
1102
               uoff_t v_offset, bool mark ATTR_UNUSED)
1103
0
{
1104
0
  size_t available;
1105
1106
0
  if (stream->istream.v_offset > v_offset)
1107
0
    i_panic("stream %s doesn't support seeking backwards",
1108
0
      i_stream_get_name(&stream->istream));
1109
1110
0
  while (stream->istream.v_offset < v_offset) {
1111
0
    (void)i_stream_read(&stream->istream);
1112
1113
0
    available = stream->pos - stream->skip;
1114
0
    if (available == 0) {
1115
0
      if (stream->istream.stream_errno != 0) {
1116
        /* read failed */
1117
0
        return;
1118
0
      }
1119
0
      io_stream_set_error(&stream->iostream,
1120
0
        "Can't seek to offset %"PRIuUOFF_T
1121
0
        ", because we have data only up to offset %"
1122
0
        PRIuUOFF_T" (eof=%d)", v_offset,
1123
0
        stream->istream.v_offset, stream->istream.eof ? 1 : 0);
1124
0
      stream->istream.stream_errno = ESPIPE;
1125
0
      return;
1126
0
    }
1127
0
    if (available <= v_offset - stream->istream.v_offset)
1128
0
      i_stream_skip(&stream->istream, available);
1129
0
    else {
1130
0
      i_stream_skip(&stream->istream,
1131
0
              v_offset - stream->istream.v_offset);
1132
0
    }
1133
0
  }
1134
0
}
1135
1136
bool i_stream_nonseekable_try_seek(struct istream_private *stream,
1137
           uoff_t v_offset)
1138
0
{
1139
0
  uoff_t start_offset = stream->istream.v_offset - stream->skip;
1140
1141
0
  if (v_offset < start_offset) {
1142
    /* have to seek backwards */
1143
0
    i_stream_seek(stream->parent, stream->parent_start_offset);
1144
0
    stream->parent_expected_offset = stream->parent_start_offset;
1145
0
    stream->skip = stream->pos = 0;
1146
0
    stream->istream.v_offset = 0;
1147
0
    stream->high_pos = 0;
1148
0
    return FALSE;
1149
0
  }
1150
1151
0
  if (v_offset <= start_offset + stream->pos) {
1152
    /* seeking backwards within what's already cached */
1153
0
    stream->skip = v_offset - start_offset;
1154
0
    stream->istream.v_offset = v_offset;
1155
0
    if (stream->high_pos == 0)
1156
0
      stream->high_pos = stream->pos;
1157
0
    stream->pos = stream->skip;
1158
0
  } else {
1159
    /* read forward */
1160
0
    i_stream_default_seek_nonseekable(stream, v_offset, FALSE);
1161
0
  }
1162
0
  return TRUE;
1163
0
}
1164
1165
static int
1166
seekable_i_stream_get_size(struct istream_private *stream)
1167
0
{
1168
0
  if (stream->cached_stream_size == UOFF_T_MAX) {
1169
0
    uoff_t old_offset = stream->istream.v_offset;
1170
0
    ssize_t ret;
1171
1172
0
    do {
1173
0
      i_stream_skip(&stream->istream,
1174
0
        i_stream_get_data_size(&stream->istream));
1175
0
    } while ((ret = i_stream_read(&stream->istream)) > 0);
1176
0
    i_assert(ret == -1);
1177
0
    if (stream->istream.stream_errno != 0)
1178
0
      return -1;
1179
1180
0
    stream->cached_stream_size = stream->istream.v_offset;
1181
0
    i_stream_seek(&stream->istream, old_offset);
1182
0
  }
1183
0
  stream->statbuf.st_size = stream->cached_stream_size;
1184
0
  return 0;
1185
0
}
1186
1187
static int
1188
i_stream_default_stat(struct istream_private *stream, bool exact)
1189
0
{
1190
0
  const struct stat *st;
1191
1192
0
  if (stream->parent == NULL)
1193
0
    return stream->istream.stream_errno == 0 ? 0 : -1;
1194
1195
0
  if (i_stream_stat(stream->parent, exact, &st) < 0) {
1196
0
    stream->istream.stream_errno = stream->parent->stream_errno;
1197
0
    return -1;
1198
0
  }
1199
0
  stream->statbuf = *st;
1200
0
  if (exact && !stream->stream_size_passthrough) {
1201
    /* exact size is not known, even if parent returned something */
1202
0
    stream->statbuf.st_size = -1;
1203
0
    if (stream->istream.seekable) {
1204
0
      if (seekable_i_stream_get_size(stream) < 0)
1205
0
        return -1;
1206
0
    }
1207
0
  } else {
1208
    /* When exact=FALSE always return the parent stat's size, even
1209
       if we know the exact value. This is necessary because
1210
       otherwise e.g. mbox code can see two different values and
1211
       think that the mbox file keeps changing. */
1212
0
  }
1213
0
  return 0;
1214
0
}
1215
1216
static int
1217
i_stream_default_get_size(struct istream_private *stream,
1218
        bool exact, uoff_t *size_r)
1219
0
{
1220
0
  if (stream->stat(stream, exact) < 0)
1221
0
    return -1;
1222
0
  if (stream->statbuf.st_size == -1)
1223
0
    return 0;
1224
1225
0
  *size_r = stream->statbuf.st_size;
1226
0
  return 1;
1227
0
}
1228
1229
void i_stream_init_parent(struct istream_private *_stream,
1230
        struct istream *parent)
1231
0
{
1232
0
  _stream->access_counter = parent->real_stream->access_counter;
1233
0
  _stream->parent = parent;
1234
0
  _stream->parent_start_offset = parent->v_offset;
1235
0
  _stream->parent_expected_offset = parent->v_offset;
1236
0
  _stream->start_offset = parent->v_offset;
1237
  /* if parent stream is an istream-error, copy the error */
1238
0
  _stream->istream.stream_errno = parent->stream_errno;
1239
0
  _stream->istream.eof = parent->eof;
1240
0
  i_stream_ref(parent);
1241
0
}
1242
1243
struct istream *
1244
i_stream_create(struct istream_private *_stream, struct istream *parent, int fd,
1245
    enum istream_create_flag flags)
1246
4.81k
{
1247
4.81k
  bool noop_snapshot = (flags & ISTREAM_CREATE_FLAG_NOOP_SNAPSHOT) != 0;
1248
1249
4.81k
  _stream->fd = fd;
1250
4.81k
  if (parent != NULL)
1251
0
    i_stream_init_parent(_stream, parent);
1252
4.81k
  else if (_stream->memarea == NULL && !noop_snapshot) {
1253
    /* The stream has no parent and no memarea yet. We'll assume
1254
       that it wants to be using memareas for the reads. */
1255
4.81k
    _stream->memarea = memarea_init_empty();
1256
4.81k
  }
1257
4.81k
  _stream->istream.real_stream = _stream;
1258
1259
4.81k
  if (_stream->iostream.close == NULL)
1260
4.81k
    _stream->iostream.close = i_stream_default_close;
1261
4.81k
  if (_stream->iostream.destroy == NULL)
1262
4.81k
    _stream->iostream.destroy = i_stream_default_destroy;
1263
4.81k
  if (_stream->seek == NULL) {
1264
0
    _stream->seek = _stream->istream.seekable ?
1265
0
      i_stream_default_seek_seekable :
1266
0
      i_stream_default_seek_nonseekable;
1267
0
  }
1268
4.81k
  if (_stream->stat == NULL)
1269
4.81k
    _stream->stat = i_stream_default_stat;
1270
4.81k
  if (_stream->get_size == NULL)
1271
4.81k
    _stream->get_size = i_stream_default_get_size;
1272
4.81k
  if (_stream->snapshot == NULL) {
1273
4.81k
    _stream->snapshot = noop_snapshot ?
1274
0
      i_stream_noop_snapshot :
1275
4.81k
      i_stream_default_snapshot;
1276
4.81k
  }
1277
4.81k
  if (_stream->iostream.set_max_buffer_size == NULL) {
1278
4.81k
    _stream->iostream.set_max_buffer_size =
1279
4.81k
      i_stream_default_set_max_buffer_size;
1280
4.81k
  }
1281
4.81k
  if (_stream->init_buffer_size == 0)
1282
4.81k
    _stream->init_buffer_size = I_STREAM_MIN_SIZE;
1283
1284
4.81k
  i_zero(&_stream->statbuf);
1285
4.81k
  _stream->statbuf.st_size = -1;
1286
4.81k
  _stream->statbuf.st_atime =
1287
4.81k
    _stream->statbuf.st_mtime =
1288
4.81k
    _stream->statbuf.st_ctime = ioloop_time;
1289
4.81k
  _stream->cached_stream_size = UOFF_T_MAX;
1290
1291
4.81k
  io_stream_init(&_stream->iostream);
1292
1293
4.81k
  if (_stream->istream.stream_errno != 0)
1294
0
    _stream->istream.eof = TRUE;
1295
1296
4.81k
  return &_stream->istream;
1297
4.81k
}
1298
1299
struct istream *i_stream_create_error(int stream_errno)
1300
0
{
1301
0
  struct istream_private *stream;
1302
1303
0
  stream = i_new(struct istream_private, 1);
1304
0
  stream->istream.closed = TRUE;
1305
0
  stream->istream.readable_fd = FALSE;
1306
0
  stream->istream.blocking = TRUE;
1307
0
  stream->istream.seekable = TRUE;
1308
0
  stream->istream.eof = TRUE;
1309
0
  stream->istream.stream_errno = stream_errno;
1310
  /* Nothing can ever actually be read from this stream, but set a
1311
     reasonable max_buffer_size anyway since some filter istreams don't
1312
     behave properly otherwise. */
1313
0
  stream->max_buffer_size = IO_BLOCK_SIZE;
1314
0
  i_stream_create(stream, NULL, -1, 0);
1315
0
  i_stream_set_name(&stream->istream, "(error)");
1316
0
  return &stream->istream;
1317
0
}
1318
1319
struct istream *
1320
i_stream_create_error_str(int stream_errno, const char *fmt, ...)
1321
0
{
1322
0
  struct istream *input;
1323
0
  va_list args;
1324
1325
0
  va_start(args, fmt);
1326
0
  input = i_stream_create_error(stream_errno);
1327
0
  io_stream_set_verror(&input->real_stream->iostream, fmt, args);
1328
0
  va_end(args);
1329
0
  return input;
1330
0
}