bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen/* @UNSAFE: whole file */
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen /* public: */
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen /* private: */
0248b1c21bed383128c0d20ff11325a2f59d0410Phil Carmodytypedef int buffer_check_sizes[COMPILE_ERROR_IF_TRUE(sizeof(struct real_buffer) > sizeof(buffer_t)) ?1:1];
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainenstatic void buffer_alloc(struct real_buffer *buf, size_t size)
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(buf->w_buffer == NULL || buf->alloced);
50ae8852cb28b11b9589a4ed5f2b54b10b1ab591Timo Sirainen buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, size);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenstatic inline void
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenbuffer_check_limits(struct real_buffer *buf, size_t pos, size_t data_size)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen i_panic("Buffer write out of range (%"PRIuSIZE_T
f874c9c2a43220d600b90456696246bf77981cd1Timo Sirainen if (new_size > buf->used && buf->used < buf->dirty) {
f874c9c2a43220d600b90456696246bf77981cd1Timo Sirainen /* clear used..dirty area */
f874c9c2a43220d600b90456696246bf77981cd1Timo Sirainen size_t max = I_MIN(I_MIN(buf->alloc, buf->dirty), new_size);
f874c9c2a43220d600b90456696246bf77981cd1Timo Sirainen memset(buf->w_buffer + buf->used, 0, max - buf->used);
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen /* always keep +1 byte allocated available in case str_c() is called
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen for this buffer. this is mainly for cases where the buffer is
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen allocated from data stack, and str_c() is called in a separate stack
b3286cc6a70ab6b4c53301aa075b16898b80c880Timo Sirainen i_panic("Buffer full (%"PRIuSIZE_T" > %"PRIuSIZE_T", "
3bbe99d30871f49610aac0417ee5951d1e740b98Timo Sirainen buffer_alloc(buf, pool_get_exp_grown_size(buf->pool, buf->alloc,
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen else if (new_size > buf->used && buf->alloced &&
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen !buf->pool->alloconly_pool && !buf->pool->datastack_pool) {
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen /* buffer's size increased: move the buffer's memory elsewhere.
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen this should help catch bugs where old pointers are tried to
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen be used to access the buffer's memory */
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainenvoid buffer_create_from_data(buffer_t *buffer, void *data, size_t size)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
49d9165e32509d6fd8fe57f65a52d41343558e9aTimo Sirainen /* clear the whole memory area. unnecessary usually, but if the
49d9165e32509d6fd8fe57f65a52d41343558e9aTimo Sirainen buffer is used by e.g. str_c() it tries to access uninitialized
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainenvoid buffer_create_from_const_data(buffer_t *buffer,
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenbuffer_t *buffer_create_dynamic(pool_t pool, size_t init_size)
09539f3db2f1b3e24f40844d8456b06d318d0fe7Timo Sirainen /* buffer_alloc() reserves +1 for str_c() NIL, so add +1 here to
09539f3db2f1b3e24f40844d8456b06d318d0fe7Timo Sirainen init_size so we can actually write that much to the buffer without
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct real_buffer *buf = (struct real_buffer *)*_buf;
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainenvoid *buffer_free_without_data(buffer_t **_buf)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct real_buffer *buf = (struct real_buffer *)*_buf;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_append(buffer_t *buf, const void *data, size_t data_size)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_write(buf, buf->used, data, data_size);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_append_c(buffer_t *buf, unsigned char chr)
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen buffer_copy(_buf, pos + data_size, _buf, pos, (size_t)-1);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_delete(buffer_t *_buf, size_t pos, size_t size)
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* delete from between */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* delete the rest of the buffer */
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_write_zero(buffer_t *_buf, size_t pos, size_t data_size)
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_append_zero(buffer_t *buf, size_t data_size)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_insert_zero(buffer_t *_buf, size_t pos, size_t data_size)
a05b31e6bb304142baf496e80072aa524e2dae3eTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen buffer_copy(_buf, pos + data_size, _buf, pos, (size_t)-1);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_copy(buffer_t *_dest, size_t dest_pos,
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen const buffer_t *_src, size_t src_pos, size_t copy_size)
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *dest = (struct real_buffer *)_dest;
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen const struct real_buffer *src = (const struct real_buffer *)_src;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_check_limits(dest, dest_pos, copy_size);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_append_buf(buffer_t *dest, const buffer_t *src,
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_copy(dest, dest->used, src, src_pos, copy_size);
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainenvoid *buffer_get_space_unsafe(buffer_t *_buf, size_t pos, size_t size)
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
38499bb33c74acc6d725204e893cfc02a5890ec7Timo Sirainenvoid *buffer_append_space_unsafe(buffer_t *buf, size_t size)
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen return buffer_get_space_unsafe(buf, buf->used, size);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainenvoid *buffer_get_modifiable_data(const buffer_t *_buf, size_t *used_size_r)
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
cc2b3aefaa55c44ae7bbe2ee74678ffcef016d91Aki Tuomi i_assert(buf->used == 0 || buf->w_buffer != NULL);
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainenvoid buffer_set_used_size(buffer_t *_buf, size_t used_size)
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainensize_t buffer_get_writable_size(const buffer_t *_buf)
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen /* we reserve +1 for str_c() NUL in buffer_check_limits(), so don't
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen include that in our return value. otherwise the caller might
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen increase the buffer's alloc size unnecessarily when it just wants
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen to access the entire buffer. */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2)
02af13e6a41b9c3e6ad1e0b692b5b9741142c221Timo Sirainen return memcmp(buf1->data, buf2->data, buf1->used) == 0;
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
bfdef55e14ade87589bd10a6a1dafce53427ecf4Timo Sirainen if (buf->pool != NULL && buf->pool->datastack_pool && buf->alloc > 0) {
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen /* this doesn't really do anything except verify the
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen stack frame */
e07b8f034b4c214e94aa5eb93d96ccbe60094b4bAki Tuomivoid buffer_truncate_rshift_bits(buffer_t *buf, size_t bits)
e07b8f034b4c214e94aa5eb93d96ccbe60094b4bAki Tuomi /* no-op if it's shorten than bits in any case.. */
e07b8f034b4c214e94aa5eb93d96ccbe60094b4bAki Tuomi /* truncate it to closest byte boundary */
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi /* remaining bits */
e07b8f034b4c214e94aa5eb93d96ccbe60094b4bAki Tuomi buffer_set_used_size(buf, I_MIN(bytes, buf->used));
e07b8f034b4c214e94aa5eb93d96ccbe60094b4bAki Tuomi unsigned char *ptr = buffer_get_modifiable_data(buf, &bytes);
e07b8f034b4c214e94aa5eb93d96ccbe60094b4bAki Tuomi /* right shift over byte array */