/src/dovecot/src/lib/istream-limit.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "istream-private.h" |
5 | | |
6 | | struct limit_istream { |
7 | | struct istream_private istream; |
8 | | |
9 | | uoff_t v_size; |
10 | | }; |
11 | | |
12 | | static void i_stream_limit_destroy(struct iostream_private *stream) |
13 | 3.01k | { |
14 | 3.01k | struct limit_istream *lstream = |
15 | 3.01k | container_of(stream, struct limit_istream, istream.iostream); |
16 | 3.01k | uoff_t v_offset; |
17 | | |
18 | 3.01k | v_offset = lstream->istream.parent_start_offset + |
19 | 3.01k | lstream->istream.istream.v_offset; |
20 | 3.01k | if (lstream->istream.parent->seekable || |
21 | 3.01k | v_offset > lstream->istream.parent->v_offset) { |
22 | | /* get to same position in parent stream */ |
23 | 3.01k | i_stream_seek(lstream->istream.parent, v_offset); |
24 | 3.01k | } |
25 | 3.01k | } |
26 | | |
27 | | static ssize_t i_stream_limit_read(struct istream_private *stream) |
28 | 8.85k | { |
29 | 8.85k | struct limit_istream *lstream = |
30 | 8.85k | container_of(stream, struct limit_istream, istream); |
31 | 8.85k | uoff_t left; |
32 | 8.85k | ssize_t ret; |
33 | 8.85k | size_t pos; |
34 | | |
35 | 8.85k | i_stream_seek(stream->parent, lstream->istream.parent_start_offset + |
36 | 8.85k | stream->istream.v_offset); |
37 | | |
38 | 8.85k | if (stream->istream.v_offset + |
39 | 8.85k | (stream->pos - stream->skip) >= lstream->v_size) { |
40 | 5.80k | stream->istream.eof = TRUE; |
41 | 5.80k | return -1; |
42 | 5.80k | } |
43 | | |
44 | 3.05k | stream->pos -= stream->skip; |
45 | 3.05k | stream->skip = 0; |
46 | | |
47 | 3.05k | stream->buffer = i_stream_get_data(stream->parent, &pos); |
48 | 3.05k | if (pos > stream->pos) |
49 | 2.96k | ret = 0; |
50 | 85 | else do { |
51 | 85 | ret = i_stream_read_memarea(stream->parent); |
52 | 85 | stream->istream.stream_errno = stream->parent->stream_errno; |
53 | 85 | stream->istream.eof = stream->parent->eof; |
54 | 85 | stream->buffer = i_stream_get_data(stream->parent, &pos); |
55 | 85 | } while (pos <= stream->pos && ret > 0); |
56 | 3.05k | if (ret == -2) |
57 | 0 | return -2; |
58 | | |
59 | 3.05k | if (lstream->v_size != UOFF_T_MAX) { |
60 | 3.05k | left = lstream->v_size - stream->istream.v_offset; |
61 | 3.05k | if (pos >= left) { |
62 | 2.90k | pos = left; |
63 | 2.90k | stream->istream.eof = TRUE; |
64 | 2.90k | } |
65 | 3.05k | } |
66 | | |
67 | 3.05k | ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : |
68 | 3.05k | (ret == 0 ? 0 : -1); |
69 | 3.05k | stream->pos = pos; |
70 | 3.05k | i_assert(ret != -1 || stream->istream.eof || |
71 | 3.05k | stream->istream.stream_errno != 0); |
72 | 3.05k | return ret; |
73 | 3.05k | } |
74 | | |
75 | | static int |
76 | | i_stream_limit_stat(struct istream_private *stream, bool exact) |
77 | 0 | { |
78 | 0 | struct limit_istream *lstream = |
79 | 0 | container_of(stream, struct limit_istream, istream); |
80 | 0 | const struct stat *st; |
81 | |
|
82 | 0 | if (i_stream_stat(stream->parent, exact, &st) < 0) { |
83 | 0 | stream->istream.stream_errno = stream->parent->stream_errno; |
84 | 0 | return -1; |
85 | 0 | } |
86 | | |
87 | 0 | stream->statbuf = *st; |
88 | 0 | if (lstream->v_size != UOFF_T_MAX) |
89 | 0 | stream->statbuf.st_size = lstream->v_size; |
90 | 0 | return 0; |
91 | 0 | } |
92 | | |
93 | | static int i_stream_limit_get_size(struct istream_private *stream, |
94 | | bool exact, uoff_t *size_r) |
95 | 0 | { |
96 | 0 | struct limit_istream *lstream = |
97 | 0 | container_of(stream, struct limit_istream, istream); |
98 | 0 | const struct stat *st; |
99 | |
|
100 | 0 | if (lstream->v_size != UOFF_T_MAX) { |
101 | 0 | *size_r = lstream->v_size; |
102 | 0 | return 1; |
103 | 0 | } |
104 | | |
105 | 0 | if (i_stream_stat(&stream->istream, exact, &st) < 0) |
106 | 0 | return -1; |
107 | 0 | if (st->st_size == -1) |
108 | 0 | return 0; |
109 | | |
110 | 0 | *size_r = st->st_size; |
111 | 0 | return 1; |
112 | 0 | } |
113 | | |
114 | | struct istream *i_stream_create_limit(struct istream *input, uoff_t v_size) |
115 | 3.01k | { |
116 | 3.01k | struct limit_istream *lstream; |
117 | | |
118 | 3.01k | lstream = i_new(struct limit_istream, 1); |
119 | 3.01k | lstream->v_size = v_size; |
120 | 3.01k | lstream->istream.max_buffer_size = input->real_stream->max_buffer_size; |
121 | | |
122 | 3.01k | lstream->istream.iostream.destroy = i_stream_limit_destroy; |
123 | 3.01k | lstream->istream.read = i_stream_limit_read; |
124 | 3.01k | lstream->istream.stat = i_stream_limit_stat; |
125 | 3.01k | lstream->istream.get_size = i_stream_limit_get_size; |
126 | | |
127 | 3.01k | lstream->istream.istream.readable_fd = input->readable_fd; |
128 | 3.01k | lstream->istream.istream.blocking = input->blocking; |
129 | 3.01k | lstream->istream.istream.seekable = input->seekable; |
130 | 3.01k | return i_stream_create(&lstream->istream, input, |
131 | 3.01k | i_stream_get_fd(input), |
132 | 3.01k | ISTREAM_HIDDEN_INPUTS_NONE, 0); |
133 | 3.01k | } |
134 | | |
135 | | struct istream *i_stream_create_range(struct istream *input, |
136 | | uoff_t v_offset, uoff_t v_size) |
137 | 0 | { |
138 | 0 | uoff_t orig_offset = input->v_offset; |
139 | 0 | struct istream *ret; |
140 | |
|
141 | 0 | input->v_offset = v_offset; |
142 | 0 | ret = i_stream_create_limit(input, v_size); |
143 | 0 | input->v_offset = orig_offset; |
144 | 0 | return ret; |
145 | 0 | } |