2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-06 09:35:32 +00:00
Files
bind/lib/isc/buffer.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

230 lines
4.9 KiB
C
Raw Normal View History

1998-12-12 20:48:14 +00:00
/*
2016-05-26 12:36:17 -07:00
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
1998-12-12 20:48:14 +00:00
*
* SPDX-License-Identifier: MPL-2.0
*
1998-12-12 20:48:14 +00:00
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
1998-12-12 20:48:14 +00:00
* See the COPYRIGHT file distributed with this work for additional
1998-10-29 02:01:29 +00:00
* information regarding copyright ownership.
1998-12-12 20:48:14 +00:00
*/
/*! \file */
2000-06-22 22:00:42 +00:00
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
1998-10-29 02:01:29 +00:00
#include <isc/buffer.h>
#include <isc/mem.h>
2016-06-21 00:25:52 +10:00
#include <isc/print.h>
#include <isc/region.h>
#include <isc/string.h>
2000-04-28 01:12:23 +00:00
#include <isc/util.h>
1998-10-29 02:01:29 +00:00
void
isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) {
/*
* Re-initialize the buffer enough to reconfigure the base of the
* buffer. We will swap in the new buffer, after copying any
* data we contain into the new buffer and adjusting all of our
* internal pointers.
*
* The buffer must not be smaller than the length of the original
* buffer.
*/
REQUIRE(b->length <= length);
REQUIRE(base != NULL);
REQUIRE(b->mctx == NULL);
if (b->length > 0U) {
(void)memmove(base, b->base, b->length);
}
b->base = base;
b->length = length;
}
1998-10-29 02:01:29 +00:00
void
1998-12-13 23:45:21 +00:00
isc_buffer_compact(isc_buffer_t *b) {
1998-10-29 02:01:29 +00:00
unsigned int length;
void *src;
1998-10-29 02:01:29 +00:00
/*
* Compact the used region by moving the remaining region so it occurs
* at the start of the buffer. The used region is shrunk by the size
* of the consumed region, and the consumed region is then made empty.
*/
REQUIRE(ISC_BUFFER_VALID(b));
1998-10-29 02:01:29 +00:00
src = isc_buffer_current(b);
length = isc_buffer_remaininglength(b);
if (length > 0U) {
(void)memmove(b->base, src, (size_t)length);
}
1998-10-29 02:01:29 +00:00
if (b->active > b->current) {
b->active -= b->current;
} else {
b->active = 0;
}
b->current = 0;
1998-10-29 02:01:29 +00:00
b->used = length;
}
1999-01-07 02:06:48 +00:00
isc_result_t
isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src) {
isc_buffer_t *dst = NULL;
isc_region_t region;
isc_result_t result;
REQUIRE(dstp != NULL && *dstp == NULL);
REQUIRE(ISC_BUFFER_VALID(src));
isc_buffer_usedregion(src, &region);
isc_buffer_allocate(mctx, &dst, region.length);
result = isc_buffer_copyregion(dst, &region);
RUNTIME_CHECK(result == ISC_R_SUCCESS); /* NOSPACE is impossible */
*dstp = dst;
return (ISC_R_SUCCESS);
}
1999-09-22 00:35:59 +00:00
isc_result_t
isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
isc_result_t result;
1999-09-22 00:35:59 +00:00
REQUIRE(ISC_BUFFER_VALID(b));
REQUIRE(r != NULL);
if (b->mctx) {
result = isc_buffer_reserve(b, r->length);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
if (r->length > isc_buffer_availablelength(b)) {
1999-09-22 00:35:59 +00:00
return (ISC_R_NOSPACE);
}
if (r->length > 0U) {
memmove(isc_buffer_used(b), r->base, r->length);
b->used += r->length;
}
1999-09-22 00:35:59 +00:00
return (ISC_R_SUCCESS);
}
void
isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
unsigned int length) {
REQUIRE(dynbuffer != NULL && *dynbuffer == NULL);
isc_buffer_t *dbuf = isc_mem_get(mctx, sizeof(isc_buffer_t));
unsigned char *bdata = isc_mem_get(mctx, length);
isc_buffer_init(dbuf, bdata, length);
dbuf->mctx = mctx;
*dynbuffer = dbuf;
}
isc_result_t
isc_buffer_reserve(isc_buffer_t *dynbuffer, unsigned int size) {
size_t len;
REQUIRE(ISC_BUFFER_VALID(dynbuffer));
len = dynbuffer->length;
if ((len - dynbuffer->used) >= size) {
return (ISC_R_SUCCESS);
}
if (dynbuffer->mctx == NULL) {
return (ISC_R_NOSPACE);
}
/* Round to nearest buffer size increment */
len = size + dynbuffer->used;
len = (len + ISC_BUFFER_INCR - 1 - ((len - 1) % ISC_BUFFER_INCR));
/* Cap at UINT_MAX */
if (len > UINT_MAX) {
len = UINT_MAX;
}
if ((len - dynbuffer->used) < size) {
2014-11-15 00:56:17 -08:00
return (ISC_R_NOMEMORY);
}
2014-11-15 00:56:17 -08:00
dynbuffer->base = isc_mem_reget(dynbuffer->mctx, dynbuffer->base,
dynbuffer->length, len);
dynbuffer->length = (unsigned int)len;
return (ISC_R_SUCCESS);
}
1999-04-29 05:59:51 +00:00
void
isc_buffer_free(isc_buffer_t **dynbuffer) {
isc_buffer_t *dbuf;
isc_mem_t *mctx;
REQUIRE(dynbuffer != NULL);
REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
REQUIRE((*dynbuffer)->mctx != NULL);
dbuf = *dynbuffer;
*dynbuffer = NULL; /* destroy external reference */
mctx = dbuf->mctx;
dbuf->mctx = NULL;
isc_mem_put(mctx, dbuf->base, dbuf->length);
isc_buffer_invalidate(dbuf);
isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
}
isc_result_t
isc_buffer_printf(isc_buffer_t *b, const char *format, ...) {
va_list ap;
int n;
isc_result_t result;
REQUIRE(ISC_BUFFER_VALID(b));
va_start(ap, format);
n = vsnprintf(NULL, 0, format, ap);
va_end(ap);
if (n < 0) {
return (ISC_R_FAILURE);
}
if (b->mctx) {
result = isc_buffer_reserve(b, n + 1);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
if (isc_buffer_availablelength(b) < (unsigned int)n + 1) {
return (ISC_R_NOSPACE);
}
va_start(ap, format);
n = vsnprintf(isc_buffer_used(b), n + 1, format, ap);
va_end(ap);
if (n < 0) {
return (ISC_R_FAILURE);
}
b->used += n;
return (ISC_R_SUCCESS);
}