Coverage Report

Created: 2026-09-14 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}