buffer.c revision 0dffa25d211be541ee3c953b23566a1a990789df
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen/* @UNSAFE: whole file */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen#include "lib.h"
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen#include "buffer.h"
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainenstruct real_buffer {
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen /* public: */
bad5981f287ff1e4094428e27178062548215a93Timo Sirainen const unsigned char *r_buffer;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen size_t used;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen /* private: */
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen unsigned char *w_buffer;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen size_t dirty, alloc;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen pool_t pool;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool alloced:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool dynamic:1;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen};
0248b1c21bed383128c0d20ff11325a2f59d0410Phil Carmodytypedef int buffer_check_sizes[COMPILE_ERROR_IF_TRUE(sizeof(struct real_buffer) > sizeof(buffer_t)) ?1:1];
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainenstatic void buffer_alloc(struct real_buffer *buf, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(buf->w_buffer == NULL || buf->alloced);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (size == buf->alloc)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(size > buf->alloc);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
50ae8852cb28b11b9589a4ed5f2b54b10b1ab591Timo Sirainen if (buf->w_buffer == NULL)
50ae8852cb28b11b9589a4ed5f2b54b10b1ab591Timo Sirainen buf->w_buffer = p_malloc(buf->pool, size);
50ae8852cb28b11b9589a4ed5f2b54b10b1ab591Timo Sirainen else
50ae8852cb28b11b9589a4ed5f2b54b10b1ab591Timo Sirainen buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, size);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen buf->alloc = size;
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->r_buffer = buf->w_buffer;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->alloced = TRUE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenstatic inline void
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenbuffer_check_limits(struct real_buffer *buf, size_t pos, size_t data_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen unsigned int extra;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen size_t new_size;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely((size_t)-1 - pos < data_size)) {
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen i_panic("Buffer write out of range (%"PRIuSIZE_T
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen " + %"PRIuSIZE_T")", pos, data_size);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen }
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen new_size = pos + data_size;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
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
f874c9c2a43220d600b90456696246bf77981cd1Timo Sirainen memset(buf->w_buffer + buf->used, 0, max - buf->used);
f874c9c2a43220d600b90456696246bf77981cd1Timo Sirainen }
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen
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
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen frame. */
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen extra = buf->dynamic ? 1 : 0;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen if (new_size + extra > buf->alloc) {
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (unlikely(!buf->dynamic)) {
b3286cc6a70ab6b4c53301aa075b16898b80c880Timo Sirainen i_panic("Buffer full (%"PRIuSIZE_T" > %"PRIuSIZE_T", "
b3286cc6a70ab6b4c53301aa075b16898b80c880Timo Sirainen "pool %s)", pos + data_size, buf->alloc,
96bd662dd0b11b4be42ebfa762f7ca328f37074aTimo Sirainen buf->pool == NULL ? "<none>" :
4940e43005d04208fe957c8e5a359f9a53a23d1fTimo Sirainen pool_get_name(buf->pool));
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen }
156a7c9057782ea8d805c4223082e1dd6041ef21Timo Sirainen
3bbe99d30871f49610aac0417ee5951d1e740b98Timo Sirainen buffer_alloc(buf, pool_get_exp_grown_size(buf->pool, buf->alloc,
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen new_size + extra));
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen }
952f5f308ab79cd46ccd79b09db3215b4237d7d4Timo Sirainen#if 0
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen else if (new_size > buf->used && buf->alloced &&
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen !buf->pool->alloconly_pool && !buf->pool->datastack_pool) {
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen void *new_buf;
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen
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 */
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen new_buf = p_malloc(buf->pool, buf->alloc);
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen memcpy(new_buf, buf->w_buffer, buf->alloc);
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen p_free(buf->pool, buf->w_buffer);
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen buf->w_buffer = new_buf;
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen buf->r_buffer = new_buf;
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen }
05a0f878264b9853d07f229ffff1bc21355157beTimo Sirainen#endif
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (new_size > buf->used)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->used = new_size;
b72b92d12bde9ca5f325a232babd74c6babef42fTimo Sirainen i_assert(buf->used <= buf->alloc);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
0a568c1e8a8066ce9d6467d891a9717bd2a24b26Phil Carmody#undef buffer_create_from_data
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainenvoid buffer_create_from_data(buffer_t *buffer, void *data, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen buf = (struct real_buffer *)buffer;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen memset(buf, 0, sizeof(*buf));
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buf->alloc = size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->r_buffer = buf->w_buffer = data;
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
49d9165e32509d6fd8fe57f65a52d41343558e9aTimo Sirainen memory */
49d9165e32509d6fd8fe57f65a52d41343558e9aTimo Sirainen memset(data, 0, size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
0a568c1e8a8066ce9d6467d891a9717bd2a24b26Phil Carmody#undef buffer_create_from_const_data
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainenvoid buffer_create_from_const_data(buffer_t *buffer,
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen const void *data, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
bdf7a0f43f555483fe6ef47fcaab4f196f3b67b4Timo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen buf = (struct real_buffer *)buffer;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen memset(buf, 0, sizeof(*buf));
bdf7a0f43f555483fe6ef47fcaab4f196f3b67b4Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buf->used = buf->alloc = size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->r_buffer = data;
bdf7a0f43f555483fe6ef47fcaab4f196f3b67b4Timo Sirainen i_assert(buf->w_buffer == NULL);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenbuffer_t *buffer_create_dynamic(pool_t pool, size_t init_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen buf = p_new(pool, struct real_buffer, 1);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->pool = pool;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buf->dynamic = TRUE;
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
09539f3db2f1b3e24f40844d8456b06d318d0fe7Timo Sirainen realloc */
09539f3db2f1b3e24f40844d8456b06d318d0fe7Timo Sirainen buffer_alloc(buf, init_size+1);
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen return (buffer_t *)buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainenvoid buffer_free(buffer_t **_buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct real_buffer *buf = (struct real_buffer *)*_buf;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_buf = NULL;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (buf->alloced)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen p_free(buf->pool, buf->w_buffer);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (buf->pool != NULL)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen p_free(buf->pool, buf);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainenvoid *buffer_free_without_data(buffer_t **_buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct real_buffer *buf = (struct real_buffer *)*_buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen void *data;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_buf = NULL;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen data = buf->w_buffer;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen p_free(buf->pool, buf);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return data;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenpool_t buffer_get_pool(const buffer_t *_buf)
1345157bfafcc329b237e55a35db8c2ad368a42aTimo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
1345157bfafcc329b237e55a35db8c2ad368a42aTimo Sirainen
1345157bfafcc329b237e55a35db8c2ad368a42aTimo Sirainen return buf->pool;
1345157bfafcc329b237e55a35db8c2ad368a42aTimo Sirainen}
1345157bfafcc329b237e55a35db8c2ad368a42aTimo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_write(buffer_t *_buf, size_t pos,
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen const void *data, size_t data_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_check_limits(buf, pos, data_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen memcpy(buf->w_buffer + pos, data, data_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_append(buffer_t *buf, const void *data, size_t data_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_write(buf, buf->used, data, data_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_append_c(buffer_t *buf, unsigned char chr)
2ca64e9cb20ca517a5a0d4ba3b73dccb2a0dd973Timo Sirainen{
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_append(buf, &chr, 1);
2ca64e9cb20ca517a5a0d4ba3b73dccb2a0dd973Timo Sirainen}
2ca64e9cb20ca517a5a0d4ba3b73dccb2a0dd973Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_insert(buffer_t *_buf, size_t pos,
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen const void *data, size_t data_size)
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen if (pos >= buf->used)
06eee07a834e38c2a95603016f9405eb7ac5857dTimo Sirainen buffer_write(_buf, pos, data, data_size);
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen else {
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen buffer_copy(_buf, pos + data_size, _buf, pos, (size_t)-1);
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen memcpy(buf->w_buffer + pos, data, data_size);
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen }
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen}
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_delete(buffer_t *_buf, size_t pos, size_t size)
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen size_t end_size;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen if (pos >= buf->used)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen return;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen end_size = buf->used - pos;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen if (size < end_size) {
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* delete from between */
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen end_size -= size;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen memmove(buf->w_buffer + pos,
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen buf->w_buffer + pos + size, end_size);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen } else {
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* delete the rest of the buffer */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen end_size = 0;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen }
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen buffer_set_used_size(_buf, pos + end_size);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen}
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_write_zero(buffer_t *_buf, size_t pos, size_t data_size)
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen{
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_check_limits(buf, pos, data_size);
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen memset(buf->w_buffer + pos, 0, data_size);
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen}
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_append_zero(buffer_t *buf, size_t data_size)
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen{
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_write_zero(buf, buf->used, data_size);
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen}
0138d3060877805f0de0bf631642de100ff96b79Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_insert_zero(buffer_t *_buf, size_t pos, size_t data_size)
a05b31e6bb304142baf496e80072aa524e2dae3eTimo Sirainen{
a05b31e6bb304142baf496e80072aa524e2dae3eTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
a05b31e6bb304142baf496e80072aa524e2dae3eTimo Sirainen
a05b31e6bb304142baf496e80072aa524e2dae3eTimo Sirainen if (pos >= buf->used)
06eee07a834e38c2a95603016f9405eb7ac5857dTimo Sirainen buffer_write_zero(_buf, pos, data_size);
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen else {
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen buffer_copy(_buf, pos + data_size, _buf, pos, (size_t)-1);
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen memset(buf->w_buffer + pos, 0, data_size);
e9219523bf8c03a1230a3a2710a2a291dc3a82a8Timo Sirainen }
a05b31e6bb304142baf496e80072aa524e2dae3eTimo Sirainen}
a05b31e6bb304142baf496e80072aa524e2dae3eTimo Sirainen
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)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *dest = (struct real_buffer *)_dest;
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen const struct real_buffer *src = (const struct real_buffer *)_src;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen size_t max_size;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen i_assert(src_pos <= src->used);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen max_size = src->used - src_pos;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen if (copy_size > max_size)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen copy_size = max_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_check_limits(dest, dest_pos, copy_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (src == dest) {
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen memmove(dest->w_buffer + dest_pos,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen src->r_buffer + src_pos, copy_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen } else {
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen memcpy(dest->w_buffer + dest_pos,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen src->r_buffer + src_pos, copy_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen }
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenvoid buffer_append_buf(buffer_t *dest, const buffer_t *src,
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen size_t src_pos, size_t copy_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_copy(dest, dest->used, src, src_pos, copy_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainenvoid *buffer_get_space_unsafe(buffer_t *_buf, size_t pos, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer_check_limits(buf, pos, size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf->w_buffer + pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
38499bb33c74acc6d725204e893cfc02a5890ec7Timo Sirainenvoid *buffer_append_space_unsafe(buffer_t *buf, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen return buffer_get_space_unsafe(buf, buf->used, size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainenvoid *buffer_get_modifiable_data(const buffer_t *_buf, size_t *used_size_r)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
bbe0ee356dc610a8d054b336534d8f33c49a36b7Timo Sirainen if (used_size_r != NULL)
bbe0ee356dc610a8d054b336534d8f33c49a36b7Timo Sirainen *used_size_r = buf->used;
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen return buf->w_buffer;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainenvoid buffer_set_used_size(buffer_t *_buf, size_t used_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen i_assert(used_size <= buf->alloc);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
f874c9c2a43220d600b90456696246bf77981cd1Timo Sirainen if (buf->used > buf->dirty)
40f114f2e12605483b21e7cf048b7c9bd9568148Timo Sirainen buf->dirty = buf->used;
40f114f2e12605483b21e7cf048b7c9bd9568148Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen buf->used = used_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainensize_t buffer_get_size(const buffer_t *_buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
b561170c84d19ef1dee3d528939d77fd38047b3fTimo Sirainen return buf->alloc;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
02af13e6a41b9c3e6ad1e0b692b5b9741142c221Timo Sirainen
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainensize_t buffer_get_writable_size(const buffer_t *_buf)
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen{
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen if (!buf->dynamic || buf->alloc == 0)
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen return buf->alloc;
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen
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. */
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen return buf->alloc-1;
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen}
e915ba86f157549b7d127f92312bc487b249df7eTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2)
02af13e6a41b9c3e6ad1e0b692b5b9741142c221Timo Sirainen{
02af13e6a41b9c3e6ad1e0b692b5b9741142c221Timo Sirainen if (buf1->used != buf2->used)
02af13e6a41b9c3e6ad1e0b692b5b9741142c221Timo Sirainen return FALSE;
02af13e6a41b9c3e6ad1e0b692b5b9741142c221Timo Sirainen
02af13e6a41b9c3e6ad1e0b692b5b9741142c221Timo Sirainen return memcmp(buf1->data, buf2->data, buf1->used) == 0;
02af13e6a41b9c3e6ad1e0b692b5b9741142c221Timo Sirainen}
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainenvoid buffer_verify_pool(buffer_t *_buf)
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen{
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen void *ret;
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen
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 */
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen ret = p_realloc(buf->pool, buf->w_buffer,
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen buf->alloc, buf->alloc);
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen i_assert(ret == buf->w_buffer);
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen }
a94f166ade968e8127b3eeda729417db9c6ad52fTimo Sirainen}