Coverage Report

Created: 2025-11-15 06:40

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