Home | History | Annotate | Line # | Download | only in isc
      1  1.1  christos /*	$NetBSD: buffer.c,v 1.1 2024/02/18 20:57:48 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  1.1  christos  *
      6  1.1  christos  * SPDX-License-Identifier: MPL-2.0
      7  1.1  christos  *
      8  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  1.1  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  1.1  christos  *
     12  1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13  1.1  christos  * information regarding copyright ownership.
     14  1.1  christos  */
     15  1.1  christos 
     16  1.1  christos /*! \file */
     17  1.1  christos 
     18  1.1  christos #include <inttypes.h>
     19  1.1  christos #include <stdarg.h>
     20  1.1  christos #include <stdbool.h>
     21  1.1  christos 
     22  1.1  christos #include <isc/buffer.h>
     23  1.1  christos #include <isc/mem.h>
     24  1.1  christos #include <isc/print.h>
     25  1.1  christos #include <isc/region.h>
     26  1.1  christos #include <isc/string.h>
     27  1.1  christos #include <isc/util.h>
     28  1.1  christos 
     29  1.1  christos void
     30  1.1  christos isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
     31  1.1  christos 	/*
     32  1.1  christos 	 * Make 'b' refer to the 'length'-byte region starting at 'base'.
     33  1.1  christos 	 * XXXDCL see the comment in buffer.h about base being const.
     34  1.1  christos 	 */
     35  1.1  christos 	ISC__BUFFER_INIT(b, base, length);
     36  1.1  christos }
     37  1.1  christos 
     38  1.1  christos void
     39  1.1  christos isc__buffer_initnull(isc_buffer_t *b) {
     40  1.1  christos 	/*
     41  1.1  christos 	 * Initialize a new buffer which has no backing store.  This can
     42  1.1  christos 	 * later be grown as needed and swapped in place.
     43  1.1  christos 	 */
     44  1.1  christos 	ISC__BUFFER_INIT(b, NULL, 0);
     45  1.1  christos }
     46  1.1  christos 
     47  1.1  christos void
     48  1.1  christos isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) {
     49  1.1  christos 	/*
     50  1.1  christos 	 * Re-initialize the buffer enough to reconfigure the base of the
     51  1.1  christos 	 * buffer.  We will swap in the new buffer, after copying any
     52  1.1  christos 	 * data we contain into the new buffer and adjusting all of our
     53  1.1  christos 	 * internal pointers.
     54  1.1  christos 	 *
     55  1.1  christos 	 * The buffer must not be smaller than the length of the original
     56  1.1  christos 	 * buffer.
     57  1.1  christos 	 */
     58  1.1  christos 	REQUIRE(b->length <= length);
     59  1.1  christos 	REQUIRE(base != NULL);
     60  1.1  christos 	REQUIRE(!b->autore);
     61  1.1  christos 
     62  1.1  christos 	if (b->length > 0U) {
     63  1.1  christos 		(void)memmove(base, b->base, b->length);
     64  1.1  christos 	}
     65  1.1  christos 
     66  1.1  christos 	b->base = base;
     67  1.1  christos 	b->length = length;
     68  1.1  christos }
     69  1.1  christos 
     70  1.1  christos void
     71  1.1  christos isc__buffer_invalidate(isc_buffer_t *b) {
     72  1.1  christos 	/*
     73  1.1  christos 	 * Make 'b' an invalid buffer.
     74  1.1  christos 	 */
     75  1.1  christos 	ISC__BUFFER_INVALIDATE(b);
     76  1.1  christos }
     77  1.1  christos 
     78  1.1  christos void
     79  1.1  christos isc_buffer_setautorealloc(isc_buffer_t *b, bool enable) {
     80  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
     81  1.1  christos 	REQUIRE(b->mctx != NULL);
     82  1.1  christos 	b->autore = enable;
     83  1.1  christos }
     84  1.1  christos 
     85  1.1  christos void
     86  1.1  christos isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
     87  1.1  christos 	/*
     88  1.1  christos 	 * Make 'r' refer to the region of 'b'.
     89  1.1  christos 	 */
     90  1.1  christos 	ISC__BUFFER_REGION(b, r);
     91  1.1  christos }
     92  1.1  christos 
     93  1.1  christos void
     94  1.1  christos isc__buffer_usedregion(const isc_buffer_t *b, isc_region_t *r) {
     95  1.1  christos 	/*
     96  1.1  christos 	 * Make 'r' refer to the used region of 'b'.
     97  1.1  christos 	 */
     98  1.1  christos 	ISC__BUFFER_USEDREGION(b, r);
     99  1.1  christos }
    100  1.1  christos 
    101  1.1  christos void
    102  1.1  christos isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
    103  1.1  christos 	/*
    104  1.1  christos 	 * Make 'r' refer to the available region of 'b'.
    105  1.1  christos 	 */
    106  1.1  christos 	ISC__BUFFER_AVAILABLEREGION(b, r);
    107  1.1  christos }
    108  1.1  christos 
    109  1.1  christos void
    110  1.1  christos isc__buffer_add(isc_buffer_t *b, unsigned int n) {
    111  1.1  christos 	/*
    112  1.1  christos 	 * Increase the 'used' region of 'b' by 'n' bytes.
    113  1.1  christos 	 */
    114  1.1  christos 	ISC__BUFFER_ADD(b, n);
    115  1.1  christos }
    116  1.1  christos 
    117  1.1  christos void
    118  1.1  christos isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
    119  1.1  christos 	/*
    120  1.1  christos 	 * Decrease the 'used' region of 'b' by 'n' bytes.
    121  1.1  christos 	 */
    122  1.1  christos 	ISC__BUFFER_SUBTRACT(b, n);
    123  1.1  christos }
    124  1.1  christos 
    125  1.1  christos void
    126  1.1  christos isc__buffer_clear(isc_buffer_t *b) {
    127  1.1  christos 	/*
    128  1.1  christos 	 * Make the used region empty.
    129  1.1  christos 	 */
    130  1.1  christos 	ISC__BUFFER_CLEAR(b);
    131  1.1  christos }
    132  1.1  christos 
    133  1.1  christos void
    134  1.1  christos isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
    135  1.1  christos 	/*
    136  1.1  christos 	 * Make 'r' refer to the consumed region of 'b'.
    137  1.1  christos 	 */
    138  1.1  christos 	ISC__BUFFER_CONSUMEDREGION(b, r);
    139  1.1  christos }
    140  1.1  christos 
    141  1.1  christos void
    142  1.1  christos isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
    143  1.1  christos 	/*
    144  1.1  christos 	 * Make 'r' refer to the remaining region of 'b'.
    145  1.1  christos 	 */
    146  1.1  christos 	ISC__BUFFER_REMAININGREGION(b, r);
    147  1.1  christos }
    148  1.1  christos 
    149  1.1  christos void
    150  1.1  christos isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
    151  1.1  christos 	/*
    152  1.1  christos 	 * Make 'r' refer to the active region of 'b'.
    153  1.1  christos 	 */
    154  1.1  christos 	ISC__BUFFER_ACTIVEREGION(b, r);
    155  1.1  christos }
    156  1.1  christos 
    157  1.1  christos void
    158  1.1  christos isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
    159  1.1  christos 	/*
    160  1.1  christos 	 * Sets the end of the active region 'n' bytes after current.
    161  1.1  christos 	 */
    162  1.1  christos 	ISC__BUFFER_SETACTIVE(b, n);
    163  1.1  christos }
    164  1.1  christos 
    165  1.1  christos void
    166  1.1  christos isc__buffer_first(isc_buffer_t *b) {
    167  1.1  christos 	/*
    168  1.1  christos 	 * Make the consumed region empty.
    169  1.1  christos 	 */
    170  1.1  christos 	ISC__BUFFER_FIRST(b);
    171  1.1  christos }
    172  1.1  christos 
    173  1.1  christos void
    174  1.1  christos isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
    175  1.1  christos 	/*
    176  1.1  christos 	 * Increase the 'consumed' region of 'b' by 'n' bytes.
    177  1.1  christos 	 */
    178  1.1  christos 	ISC__BUFFER_FORWARD(b, n);
    179  1.1  christos }
    180  1.1  christos 
    181  1.1  christos void
    182  1.1  christos isc__buffer_back(isc_buffer_t *b, unsigned int n) {
    183  1.1  christos 	/*
    184  1.1  christos 	 * Decrease the 'consumed' region of 'b' by 'n' bytes.
    185  1.1  christos 	 */
    186  1.1  christos 	ISC__BUFFER_BACK(b, n);
    187  1.1  christos }
    188  1.1  christos 
    189  1.1  christos void
    190  1.1  christos isc_buffer_compact(isc_buffer_t *b) {
    191  1.1  christos 	unsigned int length;
    192  1.1  christos 	void *src;
    193  1.1  christos 
    194  1.1  christos 	/*
    195  1.1  christos 	 * Compact the used region by moving the remaining region so it occurs
    196  1.1  christos 	 * at the start of the buffer.  The used region is shrunk by the size
    197  1.1  christos 	 * of the consumed region, and the consumed region is then made empty.
    198  1.1  christos 	 */
    199  1.1  christos 
    200  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    201  1.1  christos 
    202  1.1  christos 	src = isc_buffer_current(b);
    203  1.1  christos 	length = isc_buffer_remaininglength(b);
    204  1.1  christos 	if (length > 0U) {
    205  1.1  christos 		(void)memmove(b->base, src, (size_t)length);
    206  1.1  christos 	}
    207  1.1  christos 
    208  1.1  christos 	if (b->active > b->current) {
    209  1.1  christos 		b->active -= b->current;
    210  1.1  christos 	} else {
    211  1.1  christos 		b->active = 0;
    212  1.1  christos 	}
    213  1.1  christos 	b->current = 0;
    214  1.1  christos 	b->used = length;
    215  1.1  christos }
    216  1.1  christos 
    217  1.1  christos uint8_t
    218  1.1  christos isc_buffer_getuint8(isc_buffer_t *b) {
    219  1.1  christos 	unsigned char *cp;
    220  1.1  christos 	uint8_t result;
    221  1.1  christos 
    222  1.1  christos 	/*
    223  1.1  christos 	 * Read an unsigned 8-bit integer from 'b' and return it.
    224  1.1  christos 	 */
    225  1.1  christos 
    226  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    227  1.1  christos 	REQUIRE(b->used - b->current >= 1);
    228  1.1  christos 
    229  1.1  christos 	cp = isc_buffer_current(b);
    230  1.1  christos 	b->current += 1;
    231  1.1  christos 	result = ((uint8_t)(cp[0]));
    232  1.1  christos 
    233  1.1  christos 	return (result);
    234  1.1  christos }
    235  1.1  christos 
    236  1.1  christos void
    237  1.1  christos isc__buffer_putuint8(isc_buffer_t *b, uint8_t val) {
    238  1.1  christos 	ISC__BUFFER_PUTUINT8(b, val);
    239  1.1  christos }
    240  1.1  christos 
    241  1.1  christos uint16_t
    242  1.1  christos isc_buffer_getuint16(isc_buffer_t *b) {
    243  1.1  christos 	unsigned char *cp;
    244  1.1  christos 	uint16_t result;
    245  1.1  christos 
    246  1.1  christos 	/*
    247  1.1  christos 	 * Read an unsigned 16-bit integer in network byte order from 'b',
    248  1.1  christos 	 * convert it to host byte order, and return it.
    249  1.1  christos 	 */
    250  1.1  christos 
    251  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    252  1.1  christos 	REQUIRE(b->used - b->current >= 2);
    253  1.1  christos 
    254  1.1  christos 	cp = isc_buffer_current(b);
    255  1.1  christos 	b->current += 2;
    256  1.1  christos 	result = ((unsigned int)(cp[0])) << 8;
    257  1.1  christos 	result |= ((unsigned int)(cp[1]));
    258  1.1  christos 
    259  1.1  christos 	return (result);
    260  1.1  christos }
    261  1.1  christos 
    262  1.1  christos void
    263  1.1  christos isc__buffer_putuint16(isc_buffer_t *b, uint16_t val) {
    264  1.1  christos 	ISC__BUFFER_PUTUINT16(b, val);
    265  1.1  christos }
    266  1.1  christos 
    267  1.1  christos void
    268  1.1  christos isc__buffer_putuint24(isc_buffer_t *b, uint32_t val) {
    269  1.1  christos 	ISC__BUFFER_PUTUINT24(b, val);
    270  1.1  christos }
    271  1.1  christos 
    272  1.1  christos uint32_t
    273  1.1  christos isc_buffer_getuint32(isc_buffer_t *b) {
    274  1.1  christos 	unsigned char *cp;
    275  1.1  christos 	uint32_t result;
    276  1.1  christos 
    277  1.1  christos 	/*
    278  1.1  christos 	 * Read an unsigned 32-bit integer in network byte order from 'b',
    279  1.1  christos 	 * convert it to host byte order, and return it.
    280  1.1  christos 	 */
    281  1.1  christos 
    282  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    283  1.1  christos 	REQUIRE(b->used - b->current >= 4);
    284  1.1  christos 
    285  1.1  christos 	cp = isc_buffer_current(b);
    286  1.1  christos 	b->current += 4;
    287  1.1  christos 	result = ((unsigned int)(cp[0])) << 24;
    288  1.1  christos 	result |= ((unsigned int)(cp[1])) << 16;
    289  1.1  christos 	result |= ((unsigned int)(cp[2])) << 8;
    290  1.1  christos 	result |= ((unsigned int)(cp[3]));
    291  1.1  christos 
    292  1.1  christos 	return (result);
    293  1.1  christos }
    294  1.1  christos 
    295  1.1  christos void
    296  1.1  christos isc__buffer_putuint32(isc_buffer_t *b, uint32_t val) {
    297  1.1  christos 	ISC__BUFFER_PUTUINT32(b, val);
    298  1.1  christos }
    299  1.1  christos 
    300  1.1  christos uint64_t
    301  1.1  christos isc_buffer_getuint48(isc_buffer_t *b) {
    302  1.1  christos 	unsigned char *cp;
    303  1.1  christos 	uint64_t result;
    304  1.1  christos 
    305  1.1  christos 	/*
    306  1.1  christos 	 * Read an unsigned 48-bit integer in network byte order from 'b',
    307  1.1  christos 	 * convert it to host byte order, and return it.
    308  1.1  christos 	 */
    309  1.1  christos 
    310  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    311  1.1  christos 	REQUIRE(b->used - b->current >= 6);
    312  1.1  christos 
    313  1.1  christos 	cp = isc_buffer_current(b);
    314  1.1  christos 	b->current += 6;
    315  1.1  christos 	result = ((int64_t)(cp[0])) << 40;
    316  1.1  christos 	result |= ((int64_t)(cp[1])) << 32;
    317  1.1  christos 	result |= ((int64_t)(cp[2])) << 24;
    318  1.1  christos 	result |= ((int64_t)(cp[3])) << 16;
    319  1.1  christos 	result |= ((int64_t)(cp[4])) << 8;
    320  1.1  christos 	result |= ((int64_t)(cp[5]));
    321  1.1  christos 
    322  1.1  christos 	return (result);
    323  1.1  christos }
    324  1.1  christos 
    325  1.1  christos void
    326  1.1  christos isc__buffer_putuint48(isc_buffer_t *b, uint64_t val) {
    327  1.1  christos 	isc_result_t result;
    328  1.1  christos 	uint16_t valhi;
    329  1.1  christos 	uint32_t vallo;
    330  1.1  christos 
    331  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    332  1.1  christos 	if (ISC_UNLIKELY(b->autore)) {
    333  1.1  christos 		result = isc_buffer_reserve(&b, 6);
    334  1.1  christos 		REQUIRE(result == ISC_R_SUCCESS);
    335  1.1  christos 	}
    336  1.1  christos 	REQUIRE(isc_buffer_availablelength(b) >= 6);
    337  1.1  christos 
    338  1.1  christos 	valhi = (uint16_t)(val >> 32);
    339  1.1  christos 	vallo = (uint32_t)(val & 0xFFFFFFFF);
    340  1.1  christos 	ISC__BUFFER_PUTUINT16(b, valhi);
    341  1.1  christos 	ISC__BUFFER_PUTUINT32(b, vallo);
    342  1.1  christos }
    343  1.1  christos 
    344  1.1  christos void
    345  1.1  christos isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
    346  1.1  christos 		   unsigned int length) {
    347  1.1  christos 	ISC__BUFFER_PUTMEM(b, base, length);
    348  1.1  christos }
    349  1.1  christos 
    350  1.1  christos void
    351  1.1  christos isc__buffer_putstr(isc_buffer_t *b, const char *source) {
    352  1.1  christos 	ISC__BUFFER_PUTSTR(b, source);
    353  1.1  christos }
    354  1.1  christos 
    355  1.1  christos void
    356  1.1  christos isc_buffer_putdecint(isc_buffer_t *b, int64_t v) {
    357  1.1  christos 	unsigned int l = 0;
    358  1.1  christos 	unsigned char *cp;
    359  1.1  christos 	char buf[21];
    360  1.1  christos 	isc_result_t result;
    361  1.1  christos 
    362  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    363  1.1  christos 
    364  1.1  christos 	/* xxxwpk do it more low-level way ? */
    365  1.1  christos 	l = snprintf(buf, 21, "%" PRId64, v);
    366  1.1  christos 	RUNTIME_CHECK(l <= 21);
    367  1.1  christos 	if (ISC_UNLIKELY(b->autore)) {
    368  1.1  christos 		result = isc_buffer_reserve(&b, l);
    369  1.1  christos 		REQUIRE(result == ISC_R_SUCCESS);
    370  1.1  christos 	}
    371  1.1  christos 	REQUIRE(isc_buffer_availablelength(b) >= l);
    372  1.1  christos 
    373  1.1  christos 	cp = isc_buffer_used(b);
    374  1.1  christos 	memmove(cp, buf, l);
    375  1.1  christos 	b->used += l;
    376  1.1  christos }
    377  1.1  christos 
    378  1.1  christos isc_result_t
    379  1.1  christos isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src) {
    380  1.1  christos 	isc_buffer_t *dst = NULL;
    381  1.1  christos 	isc_region_t region;
    382  1.1  christos 	isc_result_t result;
    383  1.1  christos 
    384  1.1  christos 	REQUIRE(dstp != NULL && *dstp == NULL);
    385  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(src));
    386  1.1  christos 
    387  1.1  christos 	isc_buffer_usedregion(src, &region);
    388  1.1  christos 
    389  1.1  christos 	isc_buffer_allocate(mctx, &dst, region.length);
    390  1.1  christos 
    391  1.1  christos 	result = isc_buffer_copyregion(dst, &region);
    392  1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS); /* NOSPACE is impossible */
    393  1.1  christos 	*dstp = dst;
    394  1.1  christos 	return (ISC_R_SUCCESS);
    395  1.1  christos }
    396  1.1  christos 
    397  1.1  christos isc_result_t
    398  1.1  christos isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
    399  1.1  christos 	isc_result_t result;
    400  1.1  christos 
    401  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    402  1.1  christos 	REQUIRE(r != NULL);
    403  1.1  christos 
    404  1.1  christos 	if (ISC_UNLIKELY(b->autore)) {
    405  1.1  christos 		result = isc_buffer_reserve(&b, r->length);
    406  1.1  christos 		if (result != ISC_R_SUCCESS) {
    407  1.1  christos 			return (result);
    408  1.1  christos 		}
    409  1.1  christos 	}
    410  1.1  christos 
    411  1.1  christos 	if (r->length > isc_buffer_availablelength(b)) {
    412  1.1  christos 		return (ISC_R_NOSPACE);
    413  1.1  christos 	}
    414  1.1  christos 
    415  1.1  christos 	if (r->length > 0U) {
    416  1.1  christos 		memmove(isc_buffer_used(b), r->base, r->length);
    417  1.1  christos 		b->used += r->length;
    418  1.1  christos 	}
    419  1.1  christos 
    420  1.1  christos 	return (ISC_R_SUCCESS);
    421  1.1  christos }
    422  1.1  christos 
    423  1.1  christos void
    424  1.1  christos isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
    425  1.1  christos 		    unsigned int length) {
    426  1.1  christos 	REQUIRE(dynbuffer != NULL && *dynbuffer == NULL);
    427  1.1  christos 
    428  1.1  christos 	isc_buffer_t *dbuf = isc_mem_get(mctx, sizeof(isc_buffer_t));
    429  1.1  christos 	unsigned char *bdata = isc_mem_get(mctx, length);
    430  1.1  christos 
    431  1.1  christos 	isc_buffer_init(dbuf, bdata, length);
    432  1.1  christos 
    433  1.1  christos 	ENSURE(ISC_BUFFER_VALID(dbuf));
    434  1.1  christos 
    435  1.1  christos 	dbuf->mctx = mctx;
    436  1.1  christos 
    437  1.1  christos 	*dynbuffer = dbuf;
    438  1.1  christos }
    439  1.1  christos 
    440  1.1  christos isc_result_t
    441  1.1  christos isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size) {
    442  1.1  christos 	unsigned char *bdata;
    443  1.1  christos 	uint64_t len;
    444  1.1  christos 
    445  1.1  christos 	REQUIRE(dynbuffer != NULL);
    446  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
    447  1.1  christos 
    448  1.1  christos 	len = (*dynbuffer)->length;
    449  1.1  christos 	if ((len - (*dynbuffer)->used) >= size) {
    450  1.1  christos 		return (ISC_R_SUCCESS);
    451  1.1  christos 	}
    452  1.1  christos 
    453  1.1  christos 	if ((*dynbuffer)->mctx == NULL) {
    454  1.1  christos 		return (ISC_R_NOSPACE);
    455  1.1  christos 	}
    456  1.1  christos 
    457  1.1  christos 	/* Round to nearest buffer size increment */
    458  1.1  christos 	len = size + (*dynbuffer)->used;
    459  1.1  christos 	len = (len + ISC_BUFFER_INCR - 1 - ((len - 1) % ISC_BUFFER_INCR));
    460  1.1  christos 
    461  1.1  christos 	/* Cap at UINT_MAX */
    462  1.1  christos 	if (len > UINT_MAX) {
    463  1.1  christos 		len = UINT_MAX;
    464  1.1  christos 	}
    465  1.1  christos 
    466  1.1  christos 	if ((len - (*dynbuffer)->used) < size) {
    467  1.1  christos 		return (ISC_R_NOMEMORY);
    468  1.1  christos 	}
    469  1.1  christos 
    470  1.1  christos 	/*
    471  1.1  christos 	 * XXXMUKS: This is far more expensive than plain realloc() as
    472  1.1  christos 	 * it doesn't remap pages, but does ordinary copy. So is
    473  1.1  christos 	 * isc_mem_reallocate(), which has additional issues.
    474  1.1  christos 	 */
    475  1.1  christos 	bdata = isc_mem_get((*dynbuffer)->mctx, (unsigned int)len);
    476  1.1  christos 
    477  1.1  christos 	memmove(bdata, (*dynbuffer)->base, (*dynbuffer)->length);
    478  1.1  christos 	isc_mem_put((*dynbuffer)->mctx, (*dynbuffer)->base,
    479  1.1  christos 		    (*dynbuffer)->length);
    480  1.1  christos 
    481  1.1  christos 	(*dynbuffer)->base = bdata;
    482  1.1  christos 	(*dynbuffer)->length = (unsigned int)len;
    483  1.1  christos 
    484  1.1  christos 	return (ISC_R_SUCCESS);
    485  1.1  christos }
    486  1.1  christos 
    487  1.1  christos void
    488  1.1  christos isc_buffer_free(isc_buffer_t **dynbuffer) {
    489  1.1  christos 	isc_buffer_t *dbuf;
    490  1.1  christos 	isc_mem_t *mctx;
    491  1.1  christos 
    492  1.1  christos 	REQUIRE(dynbuffer != NULL);
    493  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
    494  1.1  christos 	REQUIRE((*dynbuffer)->mctx != NULL);
    495  1.1  christos 
    496  1.1  christos 	dbuf = *dynbuffer;
    497  1.1  christos 	*dynbuffer = NULL; /* destroy external reference */
    498  1.1  christos 	mctx = dbuf->mctx;
    499  1.1  christos 	dbuf->mctx = NULL;
    500  1.1  christos 
    501  1.1  christos 	isc_mem_put(mctx, dbuf->base, dbuf->length);
    502  1.1  christos 	isc_buffer_invalidate(dbuf);
    503  1.1  christos 	isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
    504  1.1  christos }
    505  1.1  christos 
    506  1.1  christos isc_result_t
    507  1.1  christos isc_buffer_printf(isc_buffer_t *b, const char *format, ...) {
    508  1.1  christos 	va_list ap;
    509  1.1  christos 	int n;
    510  1.1  christos 	isc_result_t result;
    511  1.1  christos 
    512  1.1  christos 	REQUIRE(ISC_BUFFER_VALID(b));
    513  1.1  christos 
    514  1.1  christos 	va_start(ap, format);
    515  1.1  christos 	n = vsnprintf(NULL, 0, format, ap);
    516  1.1  christos 	va_end(ap);
    517  1.1  christos 
    518  1.1  christos 	if (n < 0) {
    519  1.1  christos 		return (ISC_R_FAILURE);
    520  1.1  christos 	}
    521  1.1  christos 
    522  1.1  christos 	if (ISC_UNLIKELY(b->autore)) {
    523  1.1  christos 		result = isc_buffer_reserve(&b, n + 1);
    524  1.1  christos 		if (result != ISC_R_SUCCESS) {
    525  1.1  christos 			return (result);
    526  1.1  christos 		}
    527  1.1  christos 	}
    528  1.1  christos 
    529  1.1  christos 	if (isc_buffer_availablelength(b) < (unsigned int)n + 1) {
    530  1.1  christos 		return (ISC_R_NOSPACE);
    531  1.1  christos 	}
    532  1.1  christos 
    533  1.1  christos 	va_start(ap, format);
    534  1.1  christos 	n = vsnprintf(isc_buffer_used(b), n + 1, format, ap);
    535  1.1  christos 	va_end(ap);
    536  1.1  christos 
    537  1.1  christos 	if (n < 0) {
    538  1.1  christos 		return (ISC_R_FAILURE);
    539  1.1  christos 	}
    540  1.1  christos 
    541  1.1  christos 	b->used += n;
    542  1.1  christos 
    543  1.1  christos 	return (ISC_R_SUCCESS);
    544  1.1  christos }
    545