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, ®ion); 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, ®ion); 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