buffer.c revision e915ba86f157549b7d127f92312bc487b249df7e
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
12d535f8c44bbcdc1338f49aa93a0d637bd48fd9Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen/* @UNSAFE: whole file */
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include "lib.h"
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include "buffer.h"
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenstruct real_buffer {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen /* public: */
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen const unsigned char *r_buffer;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen size_t used;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen /* private: */
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen unsigned char *w_buffer;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen size_t dirty, alloc;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen pool_t pool;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen unsigned int alloced:1;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen unsigned int dynamic:1;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen};
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainentypedef int buffer_check_sizes[COMPILE_ERROR_IF_TRUE(sizeof(struct real_buffer) > sizeof(buffer_t)) ?1:1];
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenstatic void buffer_alloc(struct real_buffer *buf, size_t size)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen i_assert(buf->w_buffer == NULL || buf->alloced);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (size == buf->alloc)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen return;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen i_assert(size > buf->alloc);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, size);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->alloc = size;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->r_buffer = buf->w_buffer;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->alloced = TRUE;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenstatic inline void
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenbuffer_check_limits(struct real_buffer *buf, size_t pos, size_t data_size)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen unsigned int extra;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen size_t new_size;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (unlikely((size_t)-1 - pos < data_size)) {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen i_panic("Buffer write out of range (%"PRIuSIZE_T
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen " + %"PRIuSIZE_T")", pos, data_size);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen }
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen new_size = pos + data_size;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (new_size > buf->used && buf->used < buf->dirty) {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen /* clear used..dirty area */
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen size_t max = I_MIN(I_MIN(buf->alloc, buf->dirty), new_size);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen memset(buf->w_buffer + buf->used, 0, max - buf->used);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen }
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen /* always keep +1 byte allocated available in case str_c() is called
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen for this buffer. this is mainly for cases where the buffer is
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen allocated from data stack, and str_c() is called in a separate stack
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen frame. */
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen extra = buf->dynamic ? 1 : 0;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (new_size + extra > buf->alloc) {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (unlikely(!buf->dynamic)) {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen i_panic("Buffer full (%"PRIuSIZE_T" > %"PRIuSIZE_T", "
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen "pool %s)", pos + data_size, buf->alloc,
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->pool == NULL ? "<none>" :
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen pool_get_name(buf->pool));
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen }
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buffer_alloc(buf, pool_get_exp_grown_size(buf->pool, buf->alloc,
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen new_size + extra));
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen }
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#if 0
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen else if (new_size > buf->used && buf->alloced &&
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen !buf->pool->alloconly_pool && !buf->pool->datastack_pool) {
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen void *new_buf;
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen /* buffer's size increased: move the buffer's memory elsewhere.
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen this should help catch bugs where old pointers are tried to
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen be used to access the buffer's memory */
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen new_buf = p_malloc(buf->pool, buf->alloc);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen memcpy(new_buf, buf->w_buffer, buf->alloc);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen p_free(buf->pool, buf->w_buffer);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->w_buffer = new_buf;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->r_buffer = new_buf;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen }
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#endif
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (new_size > buf->used)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->used = new_size;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen i_assert(buf->used <= buf->alloc);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen#undef buffer_create_from_data
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainenvoid buffer_create_from_data(buffer_t *buffer, void *data, size_t size)
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen{
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen struct real_buffer *buf;
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen buf = (struct real_buffer *)buffer;
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen memset(buf, 0, sizeof(*buf));
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->alloc = size;
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen buf->r_buffer = buf->w_buffer = data;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen /* clear the whole memory area. unnecessary usually, but if the
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buffer is used by e.g. str_c() it tries to access uninitialized
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen memory */
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen memset(data, 0, size);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#undef buffer_create_from_const_data
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenvoid buffer_create_from_const_data(buffer_t *buffer,
abec3f4c5ec486c393e1513950f2d4819dcbc30fTimo Sirainen const void *data, size_t size)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct real_buffer *buf;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen
263e4b2733768062cb0b8b8917cad78fa2a04ff9Timo Sirainen buf = (struct real_buffer *)buffer;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen memset(buf, 0, sizeof(*buf));
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->used = buf->alloc = size;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->r_buffer = data;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen i_assert(buf->w_buffer == NULL);
c6ce2e251ac75fa650c7fbfa52150eae69386293Martti Rannanjärvi}
c6ce2e251ac75fa650c7fbfa52150eae69386293Martti Rannanjärvi
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenbuffer_t *buffer_create_dynamic(pool_t pool, size_t init_size)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct real_buffer *buf;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
c6ce2e251ac75fa650c7fbfa52150eae69386293Martti Rannanjärvi buf = p_new(pool, struct real_buffer, 1);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buf->pool = pool;
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen buf->dynamic = TRUE;
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen buffer_alloc(buf, init_size);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen return (buffer_t *)buf;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenvoid buffer_free(buffer_t **_buf)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct real_buffer *buf = (struct real_buffer *)*_buf;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen *_buf = NULL;
2f564433c979a41ade84b75fa10c7b46fb9781acTimo Sirainen if (buf->alloced)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen p_free(buf->pool, buf->w_buffer);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (buf->pool != NULL)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen p_free(buf->pool, buf);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenvoid *buffer_free_without_data(buffer_t **_buf)
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen{
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen struct real_buffer *buf = (struct real_buffer *)*_buf;
2f564433c979a41ade84b75fa10c7b46fb9781acTimo Sirainen void *data;
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen *_buf = NULL;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen data = buf->w_buffer;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen p_free(buf->pool, buf);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen return data;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenpool_t buffer_get_pool(const buffer_t *_buf)
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen{
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen const struct real_buffer *buf = (const struct real_buffer *)_buf;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen return buf->pool;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainenvoid buffer_reset(buffer_t *buf)
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen{
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen buffer_set_used_size(buf, 0);
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen}
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainenvoid buffer_write(buffer_t *_buf, size_t pos,
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen const void *data, size_t data_size)
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen{
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen buffer_check_limits(buf, pos, data_size);
132bfe8fcb7a1be790dc8b5bf9d155c9f060808dTimo Sirainen memcpy(buf->w_buffer + pos, data, data_size);
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen}
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainenvoid buffer_append(buffer_t *buf, const void *data, size_t data_size)
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen{
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen buffer_write(buf, buf->used, data, data_size);
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen}
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainenvoid buffer_append_c(buffer_t *buf, unsigned char chr)
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen{
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen buffer_append(buf, &chr, 1);
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen}
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainenvoid buffer_insert(buffer_t *_buf, size_t pos,
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen const void *data, size_t data_size)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen{
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (pos >= buf->used)
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen buffer_write(_buf, pos, data, data_size);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen else {
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen buffer_copy(_buf, pos + data_size, _buf, pos, (size_t)-1);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen memcpy(buf->w_buffer + pos, data, data_size);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen }
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen}
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainenvoid buffer_delete(buffer_t *_buf, size_t pos, size_t size)
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen{
71e88fae3be360e9a93b3398e743f99a6f05d2edTimo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen size_t end_size;
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen if (pos >= buf->used)
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen return;
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen end_size = buf->used - pos;
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen
71e88fae3be360e9a93b3398e743f99a6f05d2edTimo Sirainen if (size < end_size) {
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen /* delete from between */
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen end_size -= size;
206ac4273fa102500fa017f0c21a4fd72e94665aTimo Sirainen memmove(buf->w_buffer + pos,
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen buf->w_buffer + pos + size, end_size);
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen } else {
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen /* delete the rest of the buffer */
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen end_size = 0;
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen }
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen buffer_set_used_size(_buf, pos + end_size);
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen}
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainenvoid buffer_write_zero(buffer_t *_buf, size_t pos, size_t data_size)
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen{
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
ea9d9d99948cff5f9b881f79b28fa3b80da0f2a7Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buffer_check_limits(buf, pos, data_size);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen memset(buf->w_buffer + pos, 0, data_size);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenvoid buffer_append_zero(buffer_t *buf, size_t data_size)
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen{
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen buffer_write_zero(buf, buf->used, data_size);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen}
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenvoid buffer_insert_zero(buffer_t *_buf, size_t pos, size_t data_size)
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen{
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen struct real_buffer *buf = (struct real_buffer *)_buf;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen if (pos >= buf->used)
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen buffer_write_zero(_buf, pos, data_size);
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen else {
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen buffer_copy(_buf, pos + data_size, _buf, pos, (size_t)-1);
95c4f06cba717df14358ec883b1bd1aec6cbf0a1Timo Sirainen memset(buf->w_buffer + pos, 0, data_size);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen }
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainenvoid buffer_copy(buffer_t *_dest, size_t dest_pos,
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen const buffer_t *_src, size_t src_pos, size_t copy_size)
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen{
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen struct real_buffer *dest = (struct real_buffer *)_dest;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen const struct real_buffer *src = (const struct real_buffer *)_src;
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen size_t max_size;
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen i_assert(src_pos <= src->used);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen max_size = src->used - src_pos;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (copy_size > max_size)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen copy_size = max_size;
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen buffer_check_limits(dest, dest_pos, copy_size);
if (src == dest) {
memmove(dest->w_buffer + dest_pos,
src->r_buffer + src_pos, copy_size);
} else {
memcpy(dest->w_buffer + dest_pos,
src->r_buffer + src_pos, copy_size);
}
}
void buffer_append_buf(buffer_t *dest, const buffer_t *src,
size_t src_pos, size_t copy_size)
{
buffer_copy(dest, dest->used, src, src_pos, copy_size);
}
void *buffer_get_space_unsafe(buffer_t *_buf, size_t pos, size_t size)
{
struct real_buffer *buf = (struct real_buffer *)_buf;
buffer_check_limits(buf, pos, size);
return buf->w_buffer + pos;
}
void *buffer_append_space_unsafe(buffer_t *buf, size_t size)
{
return buffer_get_space_unsafe(buf, buf->used, size);
}
void *buffer_get_modifiable_data(const buffer_t *_buf, size_t *used_size_r)
{
const struct real_buffer *buf = (const struct real_buffer *)_buf;
if (used_size_r != NULL)
*used_size_r = buf->used;
return buf->w_buffer;
}
void buffer_set_used_size(buffer_t *_buf, size_t used_size)
{
struct real_buffer *buf = (struct real_buffer *)_buf;
i_assert(used_size <= buf->alloc);
if (buf->used > buf->dirty)
buf->dirty = buf->used;
buf->used = used_size;
}
size_t buffer_get_size(const buffer_t *_buf)
{
const struct real_buffer *buf = (const struct real_buffer *)_buf;
return buf->alloc;
}
size_t buffer_get_writable_size(const buffer_t *_buf)
{
const struct real_buffer *buf = (const struct real_buffer *)_buf;
if (!buf->dynamic || buf->alloc == 0)
return buf->alloc;
/* we reserve +1 for str_c() NUL in buffer_check_limits(), so don't
include that in our return value. otherwise the caller might
increase the buffer's alloc size unnecessarily when it just wants
to access the entire buffer. */
return buf->alloc-1;
}
bool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2)
{
if (buf1->used != buf2->used)
return FALSE;
return memcmp(buf1->data, buf2->data, buf1->used) == 0;
}
void buffer_verify_pool(buffer_t *_buf)
{
const struct real_buffer *buf = (const struct real_buffer *)_buf;
void *ret;
if (buf->pool != NULL && buf->pool->datastack_pool && buf->alloc > 0) {
/* this doesn't really do anything except verify the
stack frame */
ret = p_realloc(buf->pool, buf->w_buffer,
buf->alloc, buf->alloc);
i_assert(ret == buf->w_buffer);
}
}