istream.c revision 4aa7fe81503a20bc972ae625da4dd9e6996fbdbf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_unref(&(*stream)->real_stream->iostream);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenvoid i_stream_set_destroy_callback(struct istream *stream,
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_close(&stream->real_stream->iostream);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* error handling should be easier if we now just
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen assume the stream is now at EOF */
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct istream_private *stream = istream->real_stream;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* check again, in case the parent stream had been seeked
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen backwards and the previous read() didn't get us far
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* within buffer */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* have to seek forward */
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream *stream)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen /* use the fast route only if the parent stream is at the
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen expected offset */
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen expected_offset = stream->real_stream->parent_start_offset +
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (stream->real_stream->parent->v_offset != expected_offset)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return i_stream_can_optimize_seek(stream->real_stream->parent);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenconst struct stat *i_stream_stat(struct istream *stream, bool exact)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen struct istream_private *_stream = stream->real_stream;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return _stream->get_size(_stream, exact, size_r);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenbool i_stream_have_bytes_left(const struct istream *stream)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return !stream->eof || _stream->skip != _stream->pos;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen const struct istream_private *_stream = stream->real_stream;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* modify the buffer directly */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* use a temporary string to return it */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->line_str = str_new(default_pool, 256);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* the last line is missing LF and we want to return it. */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenchar *i_stream_next_line(struct istream *stream)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_error("i_stream_next_line() called for unmodifiable stream");
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* @UNSAFE */
3e25b17126e9536736d5da03697613e4c3af5f76Timo Sirainen for (i = _stream->skip; i < _stream->pos; i++) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret_buf = i_stream_next_line_finish(_stream, i);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenchar *i_stream_read_next_line(struct istream *stream)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_last_line(stream->real_stream);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenconst unsigned char *
68a4946b12583b88fa802e52ebee45cd96056772Timo Siraineni_stream_get_data(const struct istream *stream, size_t *size_r)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenunsigned char *i_stream_get_modifiable_data(const struct istream *stream,
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we need more data */
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen } while (ret > 0);
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen /* need to read more */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* we read at least some new data */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size > stream->max_buffer_size)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = stream->max_buffer_size;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen i_realloc(stream->w_buffer, old_size, stream->buffer_size);
14175321ddb88619015866978c05a27786ca4814Timo Sirainenbool i_stream_get_buffer_space(struct istream_private *stream,
14175321ddb88619015866978c05a27786ca4814Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* remove the unused bytes from beginning of buffer */
14175321ddb88619015866978c05a27786ca4814Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* buffer is full - grow it */
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen struct istream_private *stream = _stream->real_stream;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen (void)i_stream_get_buffer_space(stream, size, &size2);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Siraineni_stream_default_seek(struct istream_private *stream,
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen i_panic("stream doesn't support seeking backwards");
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen if (available <= v_offset - stream->istream.v_offset)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenstatic const struct stat *
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_default_stat(struct istream_private *stream, bool exact ATTR_UNUSED)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Siraineni_stream_default_get_size(struct istream_private *stream,
9511a40d933181045343110c8101b75887062aaeTimo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
9511a40d933181045343110c8101b75887062aaeTimo Sirainen _stream->parent_start_offset = parent->v_offset;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen _stream->abs_start_offset = parent->v_offset +
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen _stream->iostream.destroy = i_stream_default_destroy;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen _stream->get_size = i_stream_default_get_size;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen/* gcc istream.c -o teststream liblib.a -Wall -DHAVE_CONFIG_H -DSTREAM_TEST -g */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic void check_buffer(const unsigned char *data, size_t size, size_t offset)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < size; i++)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen const unsigned char *data;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen fd1 = open("teststream.1", O_RDWR | O_CREAT | O_TRUNC, 0600);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen fd2 = open("teststream.2", O_RDWR | O_CREAT | O_TRUNC, 0600);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* write initial data */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < sizeof(buf); i++)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test reading */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_get_size(input) == sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 512) == -2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, 0) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test moving data */
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen output1 = o_stream_create_fd(fd1, 512, FALSE);
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen output2 = o_stream_create_fd(fd2, 512, FALSE);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_seek(input, 1); size = sizeof(buf)-1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output2, input) == size);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(read(fd2, buf, sizeof(buf)) == size);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output1, input) == sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* test moving with limits */
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen l_input = i_stream_create_limit(input, sizeof(buf)/2, 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(o_stream_send_istream(output1, l_input) == 512);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_stream_set_max_buffer_size(input, sizeof(buf));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(input, &data, &size, sizeof(buf)-1) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* reading within limits */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 511) > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 512) == -2);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(i_stream_read_data(l_input, &data, &size, 0) > 0);