/src/dovecot/src/lib/buffer.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef BUFFER_H |
2 | | #define BUFFER_H |
3 | | |
4 | | struct buffer { |
5 | | union { |
6 | | struct { |
7 | | const void *data; |
8 | | const size_t used; |
9 | | }; |
10 | | void *priv[9]; |
11 | | }; |
12 | | }; |
13 | | |
14 | | /* WARNING: Be careful with functions that return pointers to data. |
15 | | With dynamic buffers they are valid only as long as buffer is not |
16 | | realloc()ed. You shouldn't rely on it being valid if you have modified |
17 | | buffer in any way. */ |
18 | | |
19 | | /* Create a modifiable buffer from given data. Writes past this size will |
20 | | i_panic(). */ |
21 | | void buffer_create_from_data(buffer_t *buffer, void *data, size_t size); |
22 | | /* Create a non-modifiable buffer from given data. */ |
23 | | void buffer_create_from_const_data(buffer_t *buffer, |
24 | | const void *data, size_t size); |
25 | | #define buffer_create_from_data(b,d,s) \ |
26 | | TYPE_CHECKS(void, \ |
27 | | /* NOLINTBEGIN(bugprone-sizeof-expression) */ \ |
28 | | COMPILE_ERROR_IF_TRUE(__builtin_object_size((d),1) < ((s)>0?(s):1)), \ |
29 | | /* NOLINTEND(bugprone-sizeof-expression) */ \ |
30 | | buffer_create_from_data((b), (d), (s))) |
31 | | #define buffer_create_from_const_data(b,d,s) \ |
32 | 0 | TYPE_CHECKS(void, \ |
33 | 0 | /* NOLINTBEGIN(bugprone-sizeof-expression) */ \ |
34 | 0 | COMPILE_ERROR_IF_TRUE(__builtin_object_size((d),1) < ((s)>0?(s):1)), \ |
35 | 0 | /* NOLINTEND(bugprone-sizeof-expression) */ \ |
36 | 0 | buffer_create_from_const_data((b), (d), (s))) |
37 | | |
38 | | /* Creates a dynamically growing buffer. Whenever write would exceed the |
39 | | current size it's grown. */ |
40 | | buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size); |
41 | | /* Create a dynamically growing buffer with a maximum size. Writes past the |
42 | | maximum size will i_panic(). Internally allow it to grow max_size+1 so |
43 | | str_c() NUL can be used. */ |
44 | | buffer_t *buffer_create_dynamic_max(pool_t pool, size_t init_size, |
45 | | size_t max_size); |
46 | | |
47 | | #define t_buffer_create(init_size) \ |
48 | | buffer_create_dynamic(pool_datastack_create(), (init_size)) |
49 | | |
50 | | /* Free the memory used by buffer. Not needed if the memory is free'd |
51 | | directly from the memory pool. */ |
52 | | void buffer_free(buffer_t **buf); |
53 | | /* Free the memory used by buffer structure, but return the buffer data |
54 | | unfree'd. */ |
55 | | void *buffer_free_without_data(buffer_t **buf); |
56 | | |
57 | | /* Returns the pool buffer was created with. */ |
58 | | pool_t buffer_get_pool(const buffer_t *buf) ATTR_PURE; |
59 | | |
60 | | /* Write data to buffer at specified position. If pos is beyond the buffer's |
61 | | current size, it is zero-filled up to that point (even if data_size==0). */ |
62 | | void buffer_write(buffer_t *buf, size_t pos, |
63 | | const void *data, size_t data_size); |
64 | | /* Append data to buffer. */ |
65 | | void buffer_append(buffer_t *buf, const void *data, size_t data_size); |
66 | | /* Append character to buffer. */ |
67 | | void buffer_append_c(buffer_t *buf, unsigned char chr); |
68 | | |
69 | | /* Insert the provided data into the buffer at position pos. If pos points past |
70 | | the current buffer size, the gap is zero-filled. */ |
71 | | void buffer_insert(buffer_t *buf, size_t pos, |
72 | | const void *data, size_t data_size); |
73 | | /* Delete data with the indicated size from the buffer at position pos. The |
74 | | deleted block may cross the current buffer size boundary, which is ignored. |
75 | | */ |
76 | | void buffer_delete(buffer_t *buf, size_t pos, size_t size); |
77 | | /* Replace the data in the buffer with the indicated size at position pos with |
78 | | the provided data. This is a more optimized version of |
79 | | buffer_delete(buf, pos, size); buffer_insert(buf, pos, data, data_size); */ |
80 | | void buffer_replace(buffer_t *buf, size_t pos, size_t size, |
81 | | const void *data, size_t data_size); |
82 | | |
83 | | /* Fill buffer with zero bytes. */ |
84 | | void buffer_write_zero(buffer_t *buf, size_t pos, size_t data_size); |
85 | | void buffer_append_zero(buffer_t *buf, size_t data_size); |
86 | | void buffer_insert_zero(buffer_t *buf, size_t pos, size_t data_size); |
87 | | |
88 | | /* Copy data from buffer to another. The buffers may be same in which case |
89 | | it's internal copying, possibly with overlapping positions (ie. memmove() |
90 | | like functionality). copy_size may be set to SIZE_MAX to copy the rest of |
91 | | the used data in buffer. */ |
92 | | void buffer_copy(buffer_t *dest, size_t dest_pos, |
93 | | const buffer_t *src, size_t src_pos, size_t copy_size); |
94 | | /* Append data to buffer from another. copy_size may be set to SIZE_MAX to |
95 | | copy the rest of the used data in buffer. */ |
96 | | void buffer_append_buf(buffer_t *dest, const buffer_t *src, |
97 | | size_t src_pos, size_t copy_size); |
98 | | |
99 | | /* Clone source buffer onto specified pool. Allocate extra_space extra space. */ |
100 | | static inline buffer_t * |
101 | | buffer_clone(pool_t pool, const buffer_t *src, size_t extra_space) |
102 | 0 | { |
103 | 0 | buffer_t *buf = buffer_create_dynamic(pool, src->used + extra_space); |
104 | 0 |
|
105 | 0 | buffer_append_buf(buf, src, 0, SIZE_MAX); |
106 | 0 | return buf; |
107 | 0 | } Unexecuted instantiation: fuzz-imap-utf7.c:buffer_clone Unexecuted instantiation: imap-utf7.c:buffer_clone Unexecuted instantiation: buffer.c:buffer_clone Unexecuted instantiation: data-stack.c:buffer_clone Unexecuted instantiation: event-log.c:buffer_clone Unexecuted instantiation: failures.c:buffer_clone Unexecuted instantiation: iostream-pump.c:buffer_clone Unexecuted instantiation: istream.c:buffer_clone Unexecuted instantiation: ioloop.c:buffer_clone Unexecuted instantiation: ioloop-notify-inotify.c:buffer_clone Unexecuted instantiation: ioloop-epoll.c:buffer_clone Unexecuted instantiation: lib.c:buffer_clone Unexecuted instantiation: lib-event.c:buffer_clone Unexecuted instantiation: lib-signals.c:buffer_clone Unexecuted instantiation: mempool.c:buffer_clone Unexecuted instantiation: path-util.c:buffer_clone Unexecuted instantiation: priorityq.c:buffer_clone Unexecuted instantiation: restrict-access.c:buffer_clone Unexecuted instantiation: str.c:buffer_clone Unexecuted instantiation: strescape.c:buffer_clone Unexecuted instantiation: strfuncs.c:buffer_clone Unexecuted instantiation: unichar.c:buffer_clone Unexecuted instantiation: array.c:buffer_clone Unexecuted instantiation: backtrace-string.c:buffer_clone Unexecuted instantiation: env-util.c:buffer_clone Unexecuted instantiation: event-filter.c:buffer_clone Unexecuted instantiation: event-filter-lexer.c:buffer_clone Unexecuted instantiation: iostream.c:buffer_clone Unexecuted instantiation: wildcard-match.c:buffer_clone |
108 | | /* Clone source buffer onto datastack. Allocate extra_space extra space. */ |
109 | | static inline buffer_t * |
110 | | t_buffer_clone(const buffer_t *src, size_t extra_space) |
111 | 0 | { |
112 | 0 | buffer_t *buf = buffer_create_dynamic(pool_datastack_create(), |
113 | 0 | src->used + extra_space); |
114 | 0 |
|
115 | 0 | buffer_append_buf(buf, src, 0, SIZE_MAX); |
116 | 0 | return buf; |
117 | 0 | } Unexecuted instantiation: fuzz-imap-utf7.c:t_buffer_clone Unexecuted instantiation: imap-utf7.c:t_buffer_clone Unexecuted instantiation: buffer.c:t_buffer_clone Unexecuted instantiation: data-stack.c:t_buffer_clone Unexecuted instantiation: event-log.c:t_buffer_clone Unexecuted instantiation: failures.c:t_buffer_clone Unexecuted instantiation: iostream-pump.c:t_buffer_clone Unexecuted instantiation: istream.c:t_buffer_clone Unexecuted instantiation: ioloop.c:t_buffer_clone Unexecuted instantiation: ioloop-notify-inotify.c:t_buffer_clone Unexecuted instantiation: ioloop-epoll.c:t_buffer_clone Unexecuted instantiation: lib.c:t_buffer_clone Unexecuted instantiation: lib-event.c:t_buffer_clone Unexecuted instantiation: lib-signals.c:t_buffer_clone Unexecuted instantiation: mempool.c:t_buffer_clone Unexecuted instantiation: path-util.c:t_buffer_clone Unexecuted instantiation: priorityq.c:t_buffer_clone Unexecuted instantiation: restrict-access.c:t_buffer_clone Unexecuted instantiation: str.c:t_buffer_clone Unexecuted instantiation: strescape.c:t_buffer_clone Unexecuted instantiation: strfuncs.c:t_buffer_clone Unexecuted instantiation: unichar.c:t_buffer_clone Unexecuted instantiation: array.c:t_buffer_clone Unexecuted instantiation: backtrace-string.c:t_buffer_clone Unexecuted instantiation: env-util.c:t_buffer_clone Unexecuted instantiation: event-filter.c:t_buffer_clone Unexecuted instantiation: event-filter-lexer.c:t_buffer_clone Unexecuted instantiation: iostream.c:t_buffer_clone Unexecuted instantiation: wildcard-match.c:t_buffer_clone |
118 | | |
119 | | /* Returns pointer to specified position in buffer. WARNING: The returned |
120 | | address may become invalid if you add more data to buffer. */ |
121 | | void *buffer_get_space_unsafe(buffer_t *buf, size_t pos, size_t size); |
122 | | /* Increase the buffer usage by given size, and return a pointer to beginning |
123 | | of it. */ |
124 | | void *buffer_append_space_unsafe(buffer_t *buf, size_t size); |
125 | | |
126 | | /* Like buffer_get_data(), but don't return it as const. Returns NULL if the |
127 | | buffer is non-modifiable. WARNING: The returned address may become invalid |
128 | | if you add more data to buffer. */ |
129 | | void *buffer_get_modifiable_data(const buffer_t *buf, size_t *used_size_r) |
130 | | ATTR_NULL(2); |
131 | | |
132 | | /* Set the "used size" of buffer, ie. 0 would set the buffer empty. |
133 | | Must not be used to grow buffer. The data after the buffer's new size will |
134 | | be effectively lost, because e.g. buffer_get_space_unsafe() will zero out |
135 | | the contents. */ |
136 | | void buffer_set_used_size(buffer_t *buf, size_t used_size); |
137 | | |
138 | | /* Clear the buffer. */ |
139 | | static inline void buffer_clear(buffer_t *buf) |
140 | 0 | { |
141 | 0 | buffer_set_used_size(buf, 0); |
142 | 0 | } Unexecuted instantiation: fuzz-imap-utf7.c:buffer_clear Unexecuted instantiation: imap-utf7.c:buffer_clear Unexecuted instantiation: buffer.c:buffer_clear Unexecuted instantiation: data-stack.c:buffer_clear Unexecuted instantiation: event-log.c:buffer_clear Unexecuted instantiation: failures.c:buffer_clear Unexecuted instantiation: iostream-pump.c:buffer_clear Unexecuted instantiation: istream.c:buffer_clear Unexecuted instantiation: ioloop.c:buffer_clear Unexecuted instantiation: ioloop-notify-inotify.c:buffer_clear Unexecuted instantiation: ioloop-epoll.c:buffer_clear Unexecuted instantiation: lib.c:buffer_clear Unexecuted instantiation: lib-event.c:buffer_clear Unexecuted instantiation: lib-signals.c:buffer_clear Unexecuted instantiation: mempool.c:buffer_clear Unexecuted instantiation: path-util.c:buffer_clear Unexecuted instantiation: priorityq.c:buffer_clear Unexecuted instantiation: restrict-access.c:buffer_clear Unexecuted instantiation: str.c:buffer_clear Unexecuted instantiation: strescape.c:buffer_clear Unexecuted instantiation: strfuncs.c:buffer_clear Unexecuted instantiation: unichar.c:buffer_clear Unexecuted instantiation: array.c:buffer_clear Unexecuted instantiation: backtrace-string.c:buffer_clear Unexecuted instantiation: env-util.c:buffer_clear Unexecuted instantiation: event-filter.c:buffer_clear Unexecuted instantiation: event-filter-lexer.c:buffer_clear Unexecuted instantiation: iostream.c:buffer_clear Unexecuted instantiation: wildcard-match.c:buffer_clear |
143 | | /* Clear the buffer, but also make sure any contents is zeroed out. */ |
144 | | void buffer_clear_safe(buffer_t *_buf); |
145 | | |
146 | | /* Returns the current buffer size. */ |
147 | | size_t buffer_get_size(const buffer_t *buf) ATTR_PURE; |
148 | | /* Returns how many bytes we can write to buffer without increasing its size. |
149 | | With dynamic buffers this is buffer_get_size()-1, because the extra 1 byte |
150 | | is reserved for str_c()'s NUL. */ |
151 | | size_t buffer_get_writable_size(const buffer_t *buf) ATTR_PURE; |
152 | | /* Returns the maximum number of bytes we can append to the buffer. If the |
153 | | buffer is dynamic, this is always near SIZE_MAX. */ |
154 | | size_t buffer_get_avail_size(const buffer_t *buf) ATTR_PURE; |
155 | | |
156 | | /* Returns TRUE if buffer contents are identical. */ |
157 | | bool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2); |
158 | | |
159 | | /* Returns pointer to beginning of buffer data. Current used size of buffer is |
160 | | stored in used_size if it's non-NULL. */ |
161 | | static inline const void * ATTR_NULL(2) |
162 | | buffer_get_data(const buffer_t *buf, size_t *used_size_r) |
163 | 0 | { |
164 | 0 | if (used_size_r != NULL) |
165 | 0 | *used_size_r = buf->used; |
166 | 0 | return buf->data; |
167 | 0 | } Unexecuted instantiation: fuzz-imap-utf7.c:buffer_get_data Unexecuted instantiation: imap-utf7.c:buffer_get_data Unexecuted instantiation: buffer.c:buffer_get_data Unexecuted instantiation: data-stack.c:buffer_get_data Unexecuted instantiation: event-log.c:buffer_get_data Unexecuted instantiation: failures.c:buffer_get_data Unexecuted instantiation: iostream-pump.c:buffer_get_data Unexecuted instantiation: istream.c:buffer_get_data Unexecuted instantiation: ioloop.c:buffer_get_data Unexecuted instantiation: ioloop-notify-inotify.c:buffer_get_data Unexecuted instantiation: ioloop-epoll.c:buffer_get_data Unexecuted instantiation: lib.c:buffer_get_data Unexecuted instantiation: lib-event.c:buffer_get_data Unexecuted instantiation: lib-signals.c:buffer_get_data Unexecuted instantiation: mempool.c:buffer_get_data Unexecuted instantiation: path-util.c:buffer_get_data Unexecuted instantiation: priorityq.c:buffer_get_data Unexecuted instantiation: restrict-access.c:buffer_get_data Unexecuted instantiation: str.c:buffer_get_data Unexecuted instantiation: strescape.c:buffer_get_data Unexecuted instantiation: strfuncs.c:buffer_get_data Unexecuted instantiation: unichar.c:buffer_get_data Unexecuted instantiation: array.c:buffer_get_data Unexecuted instantiation: backtrace-string.c:buffer_get_data Unexecuted instantiation: env-util.c:buffer_get_data Unexecuted instantiation: event-filter.c:buffer_get_data Unexecuted instantiation: event-filter-lexer.c:buffer_get_data Unexecuted instantiation: iostream.c:buffer_get_data Unexecuted instantiation: wildcard-match.c:buffer_get_data |
168 | | |
169 | | /* Returns the current used buffer size. */ |
170 | | static inline size_t ATTR_PURE |
171 | | buffer_get_used_size(const buffer_t *buf) |
172 | 0 | { |
173 | 0 | return buf->used; |
174 | 0 | } Unexecuted instantiation: fuzz-imap-utf7.c:buffer_get_used_size Unexecuted instantiation: imap-utf7.c:buffer_get_used_size Unexecuted instantiation: buffer.c:buffer_get_used_size Unexecuted instantiation: data-stack.c:buffer_get_used_size Unexecuted instantiation: event-log.c:buffer_get_used_size Unexecuted instantiation: failures.c:buffer_get_used_size Unexecuted instantiation: iostream-pump.c:buffer_get_used_size Unexecuted instantiation: istream.c:buffer_get_used_size Unexecuted instantiation: ioloop.c:buffer_get_used_size Unexecuted instantiation: ioloop-notify-inotify.c:buffer_get_used_size Unexecuted instantiation: ioloop-epoll.c:buffer_get_used_size Unexecuted instantiation: lib.c:buffer_get_used_size Unexecuted instantiation: lib-event.c:buffer_get_used_size Unexecuted instantiation: lib-signals.c:buffer_get_used_size Unexecuted instantiation: mempool.c:buffer_get_used_size Unexecuted instantiation: path-util.c:buffer_get_used_size Unexecuted instantiation: priorityq.c:buffer_get_used_size Unexecuted instantiation: restrict-access.c:buffer_get_used_size Unexecuted instantiation: str.c:buffer_get_used_size Unexecuted instantiation: strescape.c:buffer_get_used_size Unexecuted instantiation: strfuncs.c:buffer_get_used_size Unexecuted instantiation: unichar.c:buffer_get_used_size Unexecuted instantiation: array.c:buffer_get_used_size Unexecuted instantiation: backtrace-string.c:buffer_get_used_size Unexecuted instantiation: env-util.c:buffer_get_used_size Unexecuted instantiation: event-filter.c:buffer_get_used_size Unexecuted instantiation: event-filter-lexer.c:buffer_get_used_size Unexecuted instantiation: iostream.c:buffer_get_used_size Unexecuted instantiation: wildcard-match.c:buffer_get_used_size |
175 | | |
176 | | /* Crash if buffer was allocated from data stack and stack frame has changed. |
177 | | This can be used as an assert-like check to verify that it's valid to |
178 | | increase the buffer size here, instead of crashing only randomly when the |
179 | | buffer needs to be increased. */ |
180 | | void buffer_verify_pool(buffer_t *buf); |
181 | | |
182 | | /* This will truncate your byte buffer to contain at most |
183 | | given number of bits. |
184 | | |
185 | | 1 bits: 01 00000001 |
186 | | 2 bits: 03 00000011 |
187 | | 3 bits: 07 00000111 |
188 | | 4 bits: 0f 00001111 |
189 | | 5 bits: 1f 00011111 |
190 | | 6 bits: 3f 00111111 |
191 | | 7 bits: 7f 01111111 |
192 | | 8 bits: ff 11111111 |
193 | | 9 bits: 01ff 0000000111111111 |
194 | | 10 bits: 03ff 0000001111111111 |
195 | | 11 bits: 07ff 0000011111111111 |
196 | | 12 bits: 0fff 0000111111111111 |
197 | | 13 bits: 1fff 0001111111111111 |
198 | | 14 bits: 3fff 0011111111111111 |
199 | | 15 bits: 7fff 0111111111111111 |
200 | | 16 bits: ffff 1111111111111111 |
201 | | |
202 | | and so forth |
203 | | |
204 | | */ |
205 | | void buffer_truncate_rshift_bits(buffer_t *buf, size_t bits); |
206 | | |
207 | | enum buffer_append_result { |
208 | | /* Stream reached EOF successfully */ |
209 | | BUFFER_APPEND_OK = 0, |
210 | | /* Error was encountered */ |
211 | | BUFFER_APPEND_READ_ERROR = -1, |
212 | | /* Stream is non-blocking, call again later */ |
213 | | BUFFER_APPEND_READ_MORE = -2, |
214 | | /* Stream was consumed up to max_read_size */ |
215 | | BUFFER_APPEND_READ_MAX_SIZE = -3, |
216 | | }; |
217 | | |
218 | | /* Attempt to fully read a stream. Since this can be a network stream, it |
219 | | can return BUFFER_APPEND_READ_MORE, which means you need to call this |
220 | | function again. It is caller's responsibility to keep track of |
221 | | max_read_size in case more reading is needed. */ |
222 | | enum buffer_append_result |
223 | | buffer_append_full_istream(buffer_t *buf, struct istream *is, size_t max_read_size, |
224 | | const char **error_r); |
225 | | |
226 | | /* Attempt to fully read a file. BUFFER_APPEND_READ_MORE is never returned. */ |
227 | | enum buffer_append_result |
228 | | buffer_append_full_file(buffer_t *buf, const char *file, size_t max_read_size, |
229 | | const char **error_r); |
230 | | |
231 | | #endif |